ONO::FW::Apps::Core

package ONO::FW::Apps::Core;
################################################################################
# COPYRIGHT / LICENSE #
################################################################################
#
# This file is part of the ONO Software Project.
#
# Copyright (C) 2000-2025 Jos KIRPS [ www.kirps.com | jos_AT_kirps_DOT_com ]
# and The Joopita Project [ www.joopita.org | contact_AT_joopita_DOT_com ]
#
# This file, as well as other parts of the ONO Software Project or related
# elements, are FREE SOFTWARE available under the ARTISTIC LICENSE 2.0.
#
# This program 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.
#
# For the full license, see /ono/osr/license/LICENSE.txt, or write to
# jos_AT_kirps_DOT_com or contact_AT_joopita_DOT_com.
#
################################################################################
# END OF COPYRIGHT / LICENSE, HERE COMES THE CODE ... #
################################################################################

use strict;

use ONO::IO;
use ONO::DB;

use ONO::FW::Apps::List;
use ONO::FW::Apps::ToolBox;

use ONO::Ext::Morzino::Apps::Manager;
use ONO::Ext::Morzino::Apps::Manager::Exercises;
use ONO::FW::Apps::PDF;
use ONO::Lib::Lang::LangKitEdu;

use ONO::FW::User::Init;

use ONO::Lib::DateTime::ToolBox;
use ONO::Lib::Web::Cookie;
use ONO::Lib::Web::Client;
use ONO::Lib::Code::RandomID;
use ONO::Lib::SQL::Quote;
use ONO::Lib::Data::Numbers::Roman;
use ONO::Lib::Data::Numbers::Hexa;
use ONO::Lib::Web::BrowserTools;

use ONO::Lib::UI::Image;
use ONO::Lib::UI::Check;
use ONO::Lib::UI::Progress;

use ONO::ToolBox::DomainLang;
use ONO::ToolBox::Logfile;
use ONO::ToolBox::Auth;
use ONO::ToolBox::SendMail;

use ONO::Lib::PDF::Gen;
use ONO::Lib::PDF::Draw;
use ONO::Lib::PDF::ToolBox;

use ONO::FW::Apps::Core::Check;
use ONO::FW::Apps::Core::Graphics;
use ONO::FW::Apps::Core::Lang;
use ONO::FW::Apps::Core::LangKit;
use ONO::FW::Apps::Core::Math;
use ONO::FW::Apps::Core::Question;
use ONO::FW::Apps::Core::Save;
use ONO::FW::Apps::Core::Stats;
use ONO::FW::Apps::Core::ToolBox;
use ONO::FW::Apps::Core::Views;
use ONO::Ext::Morzino::ToolBox;
use ONO::FW::User::Screen::Dashboard::Microblog;

use ONO::Lib::Basic;
use ONO::Lib::Web::Domain;
use ONO::Lib::Data::Emojis::Basic;

#: This is the main ONO Apps Framework Core Module, which is
#: responsible for the entire logic as well as the look and feel
#: (UI) behind most apps.

###################################################################
# init
###################################################################

sub init {

#: Deprecated here, moved to ONO_FW_Apps_Core_ToolBox.

my (
$self,
$vars_ref,
) = @_;

return ONO::FW::Apps::Core::ToolBox->init($vars_ref);

}

###################################################################
# link + form
###################################################################

sub action_url_form {

#: Deprecated here, moved to ONO_FW_Apps_Core_ToolBox.

return ONO::FW::Apps::Core::ToolBox->action_url_form();

}

###################################################################
# action url vars
###################################################################

sub action_url_vars {

#: Deprecated here, moved to ONO_FW_Apps_Core_ToolBox.

return ONO::FW::Apps::Core::ToolBox->action_url_vars($_[1]);

}

###################################################################
# is the exercise running?
###################################################################

sub running {

#: Check if an app is currently in "exercise run" mode.

my $vars_ref = $_[1];
my %vars = %$vars_ref;

my $db = $_[2];

my $return = 0;

if (($vars{'output_selected'} > 1 && !$vars{'output_load'} && !$vars{'output_save'} && !$vars{'output_save_now'} && !$vars{'output_add'} && !$vars{'output_add_custom'})) {

$return++;

}

if ($vars{'output_paper_save_exec'} || $vars{'output_paper_save_target_change'} || $vars{'output_paper_save_target_app_change'}) {

$return++;

}

if ($vars{'output_web_is_running'}) {

$return++;

}

if ($vars{'output_worksheet_maker'} || $vars{'output_paper_finalize'}) {

$return++;

}

if ($vars{'exercise_id'} && $db) {

my $exercise_id = $vars{'exercise_id'};
$exercise_id =~ s~[^A-Za-z0-9]~~g;

foreach my $line (ONO::DB->select($db,"school_school_apps_storage","id_10 = '$exercise_id'")) {
my @row = ONO::DB->readcols($line);
if ($row[18] =~ /L/ && !$vars{'username'}) {
$return = 0;
}
}

}

return $return;

}

###################################################################
# block browser back button
###################################################################

sub blockbackbutton {

#: Code used to block the browser back button in certain
#: situations.

my (
$self,
$BASE,
$vars_ref,
) = @_;

if (ONO::IO->devstation) {

return qq~<!-- BlockBackButton disabled on DevStation -->~;

} else {

my %vars;
if ($vars_ref) {
%vars = %$vars_ref;
}
if ($vars{'output_worksheet_maker'}) {
return qq~<!-- BlockBackButton disabled in WorksheetMakerMode -->~;
} else {
return ONO::Lib::Web::BrowserTools->blockbackbutton($BASE);
}

}

}

###################################################################
# timer
###################################################################

sub timer {

#: Transmit timer code (online exercising mode).

my (
$self,
$output_web,
$output_web_timer_start,
) = @_;

if ($output_web) {

my $time = time();

if ($output_web_timer_start < 1) {
$output_web_timer_start = $time;
}

return qq~<input type="hidden" name="output_web_timer_start" value="$output_web_timer_start">
<input type="hidden" name="output_web_timer_now" value="$time">
~;

} else {

return "";

}


}

###################################################################
# configuration box
###################################################################

sub conf_box {

my (
$self,
$db,
$community,
$app,
$form,
$input,
$action_url,
$CONF,
$lang,
$BLK_ref,
$vars_ref,
$switches,
$OVERLAY,
) = @_;

#: This is the main app configuration screen logic, used to
#: build the initial app interface that lets users customize
#: exercises and worksheets.
#:
#: Switches:
#:
#: -a print option: auto eval
#: -A print option: -a selected by default
#: -b print option: black and white
#: -c print option: corrections
#: -C print option: -c selected by default (recommended)
#: -d print option: date
#: -D print option: -d selected by default (recommended)
#: -F folder generator mode
#: -g show game button
#: -G bigger game button
#: -h web option: allow hints, checked by default
#: -H web option: allow Hints, not checked by default
#: -i print option: item numbers
#: -I print option: -i selected by default (recommended)
#: -K allow self-(K)correction (resulthints)
#: -l allow loading settings (also see 's' and 'u')
#: -L margin left 10px
#: -m multiple choice (web mode, auto-toggle with -N)
#: -M multiple choice (print mode)
#: -n print option: number of unique copies
#: -N number of questions (web/online mode only, also see -X)
#: -o show online button
#: -O one by one, or 20 questions per page
#: -p show print button + options
#: -P custom print button
#: -Q print option: no code, no title
#: -s allow saving settings (also see 'l' and 'u')
#: -S use 'Setup' instead of 'Configure exercise' as title
#: -t replace Title by $vars{'conf_box_title'} and/or $vars{'conf_box_icon'}
#: -T margin top 10px
#: -u save PDF to server (also see 'l' and 's')
#: -U print option: unique copies disabled
#: -W maxwidth is app_conf_box_maxwidth
#: -X only one by one, no multiply questions allowed

my %BLK = %$BLK_ref;
my %vars = %$vars_ref;

if (ONO::IO->devstation) {

my $community = ONO::IO->community();
my $Community = ucfirst $community;

if ($ENV{'REQUEST_URI'} =~ m~cgi-bin/local/perl/$community/apps/(.*?)\.pl~) {

ONO::IO->mkdir("cgi-bin/local/perl/$community/$Community/Apps/Switches");
ONO::IO->store("cgi-bin/local/perl/$community/$Community/Apps/Switches/$1.txt",$switches);

}

}

if ($vars{'app_lang'}) {
$lang = $vars{'app_lang'};
}

my @txts = ONO::FW::Apps::Core::LangKit->conf_box($lang);

if (!$db) {

return qq~<div class="p20 lightred">
<div class="p10">Oops, it looks as we're experiencing some database problems right now.</div>
<div class="p10">Please check back within a few minutes, we're working on it...</div>
<div class="p10">Sorry for the inconvenience!</div>
</div>
~;

} else {

my ($BUTTONS,$PRINT_OPTS,$RELOAD,$OUTPUT_LOADSAVE,$use_multichoice);

my $TITLE = qq~<span class="hide800">$BLK{'Configure_exercise'}:</span><span class="hide inline800">$BLK{'Configure'}:</span>~;
if ($switches =~ /S/) {
$TITLE = $BLK{'Setup'};
}
if ($switches =~ /F/) {
$TITLE = $vars{'app_input_print_options_title_default'};
}

my $TITLE_ICON = "ono/setup";

if ($switches =~ /t/) {
if ($vars{'conf_box_title'}) {
$TITLE = $vars{'conf_box_title'};
}
if ($vars{'conf_box_icon'}) {
$TITLE_ICON = $vars{'conf_box_icon'};
}
}

if ($vars{'virclass'} && $vars{'virclass_user'}) {
$TITLE_ICON = "kdm/user_male";
$TITLE = $vars{'virclass_user'};
if ($vars{'virclass_user'} eq "anonymous") {
$TITLE = "$BLK{'anonymous'} ($BLK{'no_name'})";
}
}

my $AppName = ONO::FW::Apps::ToolBox->get_app_name($db,$community,$app,$lang);
if ($AppName eq ucfirst $app && $BLK{$app}) {
$AppName = $BLK{$app};
}

$vars{'app_input_print_options_title'} =~ s~ \'~\'~g;

if (!$vars{'app_input_print_options_title'}) {
$vars{'app_input_print_options_title'} = $AppName;
if ($vars{'app_input_print_options_title_default'}) {
$vars{'app_input_print_options_title'} = $vars{'app_input_print_options_title_default'};
}
}

if (ONO::IO->devstation) {
# $vars{'username'} = "jos";
}

if ($vars{'exercise'} && $vars{'exercise_id'}) {

my $exercise_id = $vars{'exercise_id'};
$exercise_id =~ s~[^A-Za-z0-9]~~g;

foreach my $line (ONO::DB->select($db,"${community}_school_apps_storage","id_10 = '$exercise_id'")) {
my @row = ONO::DB->readcols($line);

$vars{'exercise_flags'} = $row[18];

$TITLE_ICON = "apps/kate";
$TITLE = $row[6];

if ($vars{'output_web'} && $vars{'output_selected'}) {

$vars{'output_web_exercise_autostart'}++;

} else {

my $PROIMG = ONO::FW::User::Init->profileimage($row[4],32);
my $USER = ONO::DB->get($db,"realname","${community}_community_profiles","username = '$row[4]'");

$row[10] = ONO::Lib::DateTime::ToolBox->convert("date",$row[10],"U",$lang);

$CONF .= qq~<tr class="vtop">
<td>$PROIMG</td>
<td>
<div class="lh125">
<div>$BLK{'by'} $USER</div>
<div class="small"><a href="/users/$row[4]/" class="col9" target="_parent">/users/$row[4]/</a></div>
</div>
</td>
</tr>
<tr>
<td></td>
<td>$row[10]</td>
</tr>
~;

if ($vars{'app_input_number_of_questions'}) {

my $LABEL = $BLK{'questions'};
if ($vars{'app_input_number_of_questions_alt_label'}) {
$LABEL = $vars{'app_input_number_of_questions_alt_label'};
}

$CONF .= qq~ <tr>
<td></td>
<td><span class="bold">$vars{'app_input_number_of_questions'}</span> $LABEL</td>
</tr>
~;

}

for (my $i = 8; $i < 10; $i++) {

if ($row[$i] =~ /[A-Za-z0-0]/) {

$CONF .= qq~<tr class="vtop">
<td><img class="block32" src="/ono/osr/images/icons/crystal/32x32/ono/help.png" alt=""></td>
<td>$row[$i]</td>
</tr>
~;

}

}

# -c required for corrections
# -e required for e-mail report
# -p required for print

# as defined in ONO_FW_Edu_Apps_Exercises:

# -c allow printing correcions
# -e e-mail reports to owner
# -E e-mail reports to all classroom teachers
# -H don't allow hints
# -L login required (visitors can't run the exercise)
# -p allow printing

foreach my $flag ('c','p') {
if ($row[18] !~ /$flag/) {
$switches =~ s~$flag~~g;
}
}

}
}

}

if ($switches =~ /h/i && $vars{'exercise_flags'} !~ /H/ && $vars{'output_web'}) {

my $checked;
if ($switches =~ /h/) {
$checked = 1;
}

my $SWITCH = ONO::Lib::UI::Check->switch("app_input_allow_hints",$checked,"r");

$CONF .= qq~<tr>
<td style="padding-top:10px">$SWITCH</td>
<td style="padding-top:10px">$txts[14]</td>
</tr>
~;
}

if (($switches =~ /m/ && $vars{'output_web'} && !$vars{'exercise'}) || ($switches =~ /M/ && $vars{'output_paper'})) {

$use_multichoice++;

my ($JS1,$JS2);

if ($switches =~ /o/ && $switches =~ /O/ && $vars{'output_web'}) {

($JS1,$JS2) = (
"onojs_class('app_input_tr_multiple_questions_id','trans30');ono_ui_switch_app_input_multiple_questions_per_page_off();",
"onojs_class('app_input_tr_multiple_questions_id','trans100');ono_ui_switch_app_input_multiple_questions_per_page_on();",
);

}

my $SWITCH = ONO::Lib::UI::Check->switch("app_input_multiple_choice",$vars{'app_input_multiple_choice'},"Jr","",$JS1,$JS2);

my $PAD;
if ($switches !~ /H/) {
$PAD = qq~ style="padding-top:10px"~;
}

# app_input_multiple_choice_displayed can be used to test if this option has already been offered
# this is used by vocabulary for example, to make custom group selection possible

$CONF .= qq~<tr>
<td$PAD>$SWITCH<input type="hidden" name="app_input_multiple_choice_displayed" value="1"></td>
<td$PAD>$BLK{'multiple_choice'}</td>
</tr>
~;

}

if ($switches =~ /o/ && !$vars{'output_paper'}) { # && !$vars{'output_save'} && !$vars{'output_save_now'}) {

my $output_add;
foreach my $key (keys %vars) {
if ($key =~ /^output_add/) {
$output_add++;
}
}

if ($switches =~ /O/ && ($vars{'output_web'} || $vars{'output_save'} || $vars{'output_save_now'} || $output_add) && !$vars{'exercise'}) {

my $chk = 1;
my $switch_switches;

if ($switches =~ /X/) {
$chk = 0;
$switch_switches .= "d";
}

if ($vars{'output_save'} && !$vars{'output_save_now'}) {
$chk = 0;
}

my $SWITCH = ONO::Lib::UI::Check->switch("app_input_multiple_questions_per_page",$chk,"rs$switch_switches");

my $PAD;
if ($switches !~ /H/ && !$use_multichoice) {
$PAD = qq~ style="padding-top:10px"~;
}

$CONF .= qq~<tr id="app_input_tr_multiple_questions_id">
<td$PAD>$SWITCH</td>
<td$PAD>$txts[13] <span class="small col9">(max 20)</span></td>
</tr>
~;

}

if ($vars{'output_web_custom_text'}) {
$BLK{'online_training'} = $vars{'output_web_custom_text'};
}

if ($switches =~ /N/ && $vars{'output_web'} && !$vars{'exercise'}) {

my $optional;
if (!$vars{'app_input_number_of_questions'}) {
$optional = qq~ <span class="small col9 hide1000">($BLK{'optional'})</span>~;

# this was changed in june 2021, to always set a default value, hope it won't cause any problems anywhere:
$vars{'app_input_number_of_questions'} = 20;
}

if ($vars{'app_input_number_of_questions_alt_label'}) {
$txts[9] = $vars{'app_input_number_of_questions_alt_label'};
}

$BUTTONS .= qq~<table class="default_table">
<tr>
<td class="p0">
<input type="submit" name="output_web" value="$BLK{'online_training'}" class="button_green mb10">
<input type="hidden" name="output_cookie_store" value="1">
</td>
<td class="pad5_2">
<div class="mb10">
<input type="number" name="app_input_number_of_questions" value="$vars{'app_input_number_of_questions'}"
maxlength="3" min="1" max="500" step="1" class="center" style="width:50px" placeholder="?">
</div>
</td>
<td><div class="mb10">$txts[9]$optional</div></td>
</tr>
</table>
~;
} else {

if (!$vars{'username'} && $vars{'exercise_flags'} =~ /L/) {

$BUTTONS .= ONO::FW::Apps::Core::LangKit->login_required($lang);

} else {

$BUTTONS .= qq~<input type="submit" name="output_web" value="$BLK{'online_training'}" class="button_green mb10">
<input type="hidden" name="app_input_number_of_questions" value="$vars{'app_input_number_of_questions'}">
~;

}

}

}

if ($switches =~ /g/) {

my $BIG;
if ($switches =~ /G/) {
$BIG = " button_big";
}

$BUTTONS .= qq~<input type="submit" name="output_game" value="$BLK{'start_game'}" class="button_green$BIG mb10">
<input type="hidden" name="output_cookie_store" value="1">
~;
}

if ($switches =~ /N/ && ($vars{'output_save'} || $vars{'output_save_now'})) {
$CONF .= qq~<tr>
<td>
<input type="number" name="app_input_number_of_questions" value="$vars{'app_input_number_of_questions'}"
maxlength="3" min="1" max="500" step="1" class="center mr5" style="width:50px;float:right" placeholder="?">
</td>
<td>$txts[12] <span class="small col9">($BLK{'optional'}, $BLK{'recommended'})</span></td>
</tr>
~;
}

if ($switches =~ /p/ && !$vars{'output_web'} && !$vars{'output_save'} && !$vars{'output_save_now'}) {
if ($vars{'output_paper'}) {
$BLK{'print_worksheet'} = $BLK{'print'};
$BUTTONS .= qq~<input type="hidden" name="output_cookie_store" value="1">~;
}
if ($vars{'output_paper_save'}) {
$BLK{'print_worksheet'} = "$BLK{'save'} (PDF)";
$BUTTONS .= qq~<input type="hidden" name="output_paper_save_exec" value="1">~;
}
if ($vars{'output_paper_custom_text'}) {
$BLK{'print_worksheet'} = $vars{'output_paper_custom_text'};
}

if ($vars{'output_paper_button_save_pdf'} || $vars{'output_paper_num_of_pages'}) {

$BUTTONS .= qq~<table class="default_table ml10 fl">
<tr>
~;

if ($vars{'output_paper_num_of_pages'}) {

my $PAGES = qq~<option value="1">1 $BLK{'page'}</option>~;
for (my $p = 2; $p < 11; $p++) {
my $sel;
if ($p == $vars{'output_paper_num_of_pages'}) {
$sel = " selected";
}
$PAGES .= qq~<option value="$p"$sel>$p $BLK{'pages'}</option>~;
}

$BUTTONS .= qq~ <td class="p0">
<div class="mb10 mr10"><div class="select"><select name="output_paper_num_of_pages">$PAGES</select></div></div>
</td>
~;

}

$BUTTONS .= qq~ <td class="p0">
<input type="submit" name="output_paper" value="$BLK{'print_worksheet'}" class="button_green mb10">
</td>
~;

if ($vars{'output_paper_button_save_pdf'} && !$vars{'output_paper'}) {

$BUTTONS .= qq~ <td class="p0">
<input type="submit" name="output_paper_save" value="$BLK{'save'} (PDF)" class="button_green mb10 ml5">
</td>
~;

}

if ($switches =~ /K/ && !$vars{'output_paper'}) {

$BUTTONS .= qq~<td class="p0"><div class="inline mb5"><table class="default_table ml5 mb5">~;
$BUTTONS .= ONO::FW::Apps::ToolBox->conf_input("resulthints", $BLK_ref,\%vars,"","S","ai");
$BUTTONS .= qq~</table></div></td>~;

}

$BUTTONS .= qq~ </tr>
</table>
~;

} else {

$BUTTONS .= qq~<input type="submit" name="output_paper" value="$BLK{'print_worksheet'}" class="button_green mb10">~;

}

if ($vars{'output_paper_add_button'} && $vars{'output_paper_add_button_text'}) {
if ($vars{'output_paper_add_button_color'} eq "lightgreen") {
$vars{'output_paper_add_button_color'} = "_green";
$vars{'output_paper_add_button_style'} = "background-color:#bbee55;border-color:#bbee55";
}
my $BUT = qq~<input type="submit" name="$vars{'output_paper_add_button'}" value="$vars{'output_paper_add_button_text'}"
class="button$vars{'output_paper_add_button_color'}" style="$vars{'output_paper_add_button_style'}">~;
if ($vars{'output_paper_add_button_hint'}) {
$BUT = qq~<div class="rel fl" onmouseover="onojs_block('output_paper_add_button_hint');" onmouseout="onojs_hide('output_paper_add_button_hint');">
<div id="output_paper_add_button_hint" class="abs hide" style="top:-64px;left:-10px">
<div class="box_paper nowrap">
$vars{'output_paper_add_button_hint'}
</div>
<img class="block24 abs" src="/ono/osr/images/arrows/nuvola/white32shadow/nav_down.png" style="bottom:-23px;left:10px" alt="">
</div>
$BUT
</div>
~;
}
$BUTTONS .= $BUT;
}
}

if ($switches =~ /P/) {
$BUTTONS .= qq~<input type="submit" name="output_print_custom" value="$BLK{'print'}" class="button_green">~;
}

if ($switches =~ /s/ && ($vars{'output_save'} || $vars{'output_save_now'})) {

$TITLE = ucfirst $txts[1].":";
$TITLE_ICON = "actions/filesave";

$BUTTONS = qq~<input type="submit" name="output_save_now" value="$BLK{'save'}" class="button_green mb10">~;

if ($vars{'output_save_now'}) {
$BUTTONS .= qq~<a href="$action_url" class="button_yellow">$BLK{'cancel'}</a>
<span class="col9 small italic"> $BLK{'*'}) $BLK{'required_fields'}</span>
~;
}
}

if ($vars{'output_save_now'} && $vars{'username'}) {

my (
$sec,$min,$hour,
$mday,$mon,$year,
$wday,$yday,$timestamp
) = ONO::Lib::DateTime::ToolBox->get;

my $DATE = ONO::Lib::DateTime::ToolBox->select_date("app_input_save_date",$year-1,$year+3,"$year$mon$mday",$lang,"mnPT");
my $BG;

if (!$vars{'app_input_save_name'}) {
$vars{'app_input_save_name'} = $AppName;
}
if ($vars{'app_input_save_target'} && !$vars{'app_input_save_name'}) {
$BG = qq~ class="bg_red"~;
}

$CONF = qq~<tr$BG>
<td class="tar">$BLK{'title'}$BLK{'*'}:</td>
<td><input type="text" name="app_input_save_name" value="$vars{'app_input_save_name'}" class="w95" placeholder="$BLK{'untitled'}"></td>
</tr>
<tr>
<td></td>
<td class="p5"></td>
</tr>
<tr>
<td class="tar">$BLK{'date'}:</td>
<td class="p0">$DATE</td>
</tr>
<tr>
<td></td>
<td class="p5"></td>
</tr>
~;

my $sql_ref = ONO::Lib::SQL::Quote->vars(\%vars);
my %sql = %$sql_ref;

if ($vars{'app_input_save_target'} && $vars{'app_input_save_name'}) {

my ($BRANCH,$CAT,%dis);

my $TARGET = "$txts[2] ($vars{'username'})";
my $TARGET_ICON = "filesystems/folder";

if ($vars{'app_input_save_target'} > 0) {

$TARGET = ONO::DB->get($db,"fullname","${community}_school_virclass","id = '$sql{'app_input_save_target'}'");
$TARGET .= qq~ <span class="col9">(#$sql{'app_input_save_target'})</span>~;
$TARGET_ICON = "ono/virclass";
$BRANCH = ONO::Ext::Morzino::ToolBox->branch_select($vars{'app_input_save_target'},"","s");

}

if (!$BRANCH) {
$dis{'branch'} = " disabled";
}
if (!$CAT) {
$dis{'cat'} = " disabled";
}

$CONF .= qq~<tr>
<td class="tar">$BLK{'target'}$BLK{'*'}:</td>
<td class="p0">
<table class="default_table">
<tr>
<td><img class="block24" src="/ono/osr/images/icons/crystal/32x32/$TARGET_ICON.png" alt=""></td>
<td>$TARGET</td>
</tr>
</table>
<input type="hidden" name="app_input_save_target" value="$vars{'app_input_save_target'}">
<input type="hidden" name="app_input_saveready" value="1">
</td>
</tr>
<tr>
<td></td>
<td class="p2"></td>
</tr>
<tr>
<td class="tar">$BLK{'branch'}:</td>
<td>
<div class="select"><select name="app_input_save_branch"$dis{'branch'}>
<option value="">$BLK{'none'}</option>
<option value="">----</option>
$BRANCH
</select></div>
</td>
</tr>
<tr>
<td class="tar">$BLK{'category'}:</td>
<td>
<div class="select"><select name="app_input_save_category"$dis{'cat'}>
<option value="">$BLK{'none'}</option>
<option value="">----</option>
$CAT
</select></div>
</td>
</tr>
<tr>
<td></td>
<td class="p2"></td>
</tr>
<tr class="vtop">
<td class="tar">$BLK{'info'}:</td>
<td><textarea class="w95 h50" placeholder="$BLK{'optional'}...">$vars{'app_input_save_description'}</textarea></td>
</tr>
~;

my $SWITCH = ONO::Lib::UI::Check->switch("app_input_save_flag_L",0,"r");

$CONF .= qq~<tr class="vtop">
<td>$SWITCH</td>
<td class="">$txts[21]</td>
</tr>
~;

my $email = ONO::DB->get($db,"email","${community}_community_users","username = '$vars{'username'}'");
if ($email =~ /^(.*?)\@(.*?)\.(.*?)$/) {

my $SWITCH = ONO::Lib::UI::Check->switch("app_input_save_flag_e",0,"r");

$CONF .= qq~<tr class="vtop">
<td>$SWITCH</td>
<td class=""><div class="lh100">$txts[16] <span class="col9">($email)</span></div></td>
</tr>
~;

if ($vars{'app_input_save_target'} > 0) {

my $SWITCH = ONO::Lib::UI::Check->switch("app_input_save_flag_E",0,"mr");

$CONF .= qq~<tr class="vtop">
<td></td>
<td class="p0">
<table class="default_table">
<tr>
<td>$SWITCH</td>
<td><div class="lh100 small">$txts[18]</div></td>
</tr>
</table>
</td>
</tr>
~;
}

}


} else {

my $VIRCLASS = ONO::Ext::Morzino::Apps::Manager::Exercises->virclass_targets($db,$community,$vars{'username'});

$CONF .= qq~<tr>
<td class="tar">$BLK{'target'}$BLK{'*'}:</td>
<td>
<div class="select"><select name="app_input_save_target">
<option value="user">$txts[2] ($vars{'username'})</option>
$VIRCLASS
</select></div>
</td>
</tr>
~;
}

foreach my $key (keys %vars) {
if (($key =~ /^app_input_/ || $key =~ /^app_storage_/) && $key !~ /^app_input_save_/) {
$CONF .= qq~<input type="hidden" name="$key" value="$vars{$key}">~;
}
}

if ($vars{'app_input_save_target'} && $vars{'app_input_save_name'} && $vars{'app_input_saveready'}) {

my $ID1 = ONO::Lib::Code::RandomID->make(10);
my $ID2 = ucfirst ONO::Lib::Code::RandomID->make(32);

if ($sql{'app_input_save_target'} < 1) {
$sql{'app_input_save_target'} = 0;
}

my $DATE = ONO::Lib::DateTime::ToolBox->convert("date","$vars{'app_input_save_date_year'}$vars{'app_input_save_date_month'}$vars{'app_input_save_date_day'}","mU",$lang);
my $DATESAVE = ONO::Lib::DateTime::ToolBox->select_date_saver("app_input_save_date",$vars_ref);
my $FLAGS;

foreach my $key (keys %vars) {
if ($key =~ /^app_input_save_flag_(.*?)$/ && $vars{$key}) {
$FLAGS .= $1;
}
}
$FLAGS =~ s~[^A-Za-z0-9]~~g;

ONO::DB->command(
$db,
"INSERT INTO ${community}_school_apps_storage
(id_10,exercise,app,username,virclass,
name,description,date,branch,flags,
creation_username,creation_timestamp,modification_username,modification_timestamp) VALUES
('$ID1','$ID2','$app','$vars{'username'}','$sql{'app_input_save_target'}',
'$sql{'app_input_save_name'}','$sql{'app_input_save_description'}','$DATESAVE','$sql{'app_input_save_branch'}','$FLAGS',
'$vars{'username'}','$timestamp','$vars{'username'}','$timestamp');",
);

my ($DATA1,$DATA2,$counter);
foreach my $key (keys %vars) {
if ($key =~ /^app_input_/ && $key !~ /^app_input_save/) {
$DATA1 .= qq~$key:$vars{$key}\n~;
}
if ($key =~ /^app_storage_/ && $key !~ /^app_storage_type_spacer/) {
$counter++;
my $count = ONO::Lib::Basic->add_leading_zeroes($counter,3);
$DATA2 .= qq~$key:$vars{$key}\n~;
}
}

my $DIR = "var/community/${community}/apps/storage/".ONO::IO->deepdir($ID1)."/$ID1";

ONO::IO->mkpath($DIR);
ONO::IO->store("$DIR/config.txt",$DATA1);

if (!ONO::IO->exists("var/community/${community}/apps/configs/$app.txt") || int(rand(100)) == 50 || ONO::IO->devstation) {

ONO::IO->mkpath("var/community/${community}/apps/configs");
ONO::IO->store("var/community/${community}/apps/configs/$app.txt",$DATA2);

}

$CONF = qq~<tr class="vtop">
<td><img class="block24" src="/ono/osr/images/icons/ono/32x32/isok.png" alt=""></td>
<td>$txts[6] '<span class="bold">$vars{'app_input_save_name'}</span>' <span class="col9">($DATE)</span>.</td>
</tr>
~;
$BUTTONS = qq~<a href="$action_url" class="button_green">$txts[7]</a>
<a href="/exercises/" class="button_yellow" target="_parent">$txts[8] (own or virclass)</a>
~;

}

}

if (!$vars{'username'} && ($vars{'output_save'} || $vars{'output_save_now'} || $vars{'output_paper_save'})) {

$vars{'login_required'}++;

$CONF = qq~<tr>
<td></td>
<td>
<div style="padding:10px 20px 0px 20px">
<div class="bold lightred mb5">$txts[3]</div>
<div class="ml20">$txts[4] $txts[5] $BLK{'Thank_you'}!</div>
</div>
</td>
</tr>
~;
$BUTTONS = qq~<div class="inline">
<a href="/login/" class="button_green ml20" target="_parent">$BLK{'signup'} / $BLK{'login'}</a>
<a href="$action_url" class="button_yellow">$BLK{'cancel'}</a>
</div>
<table class="default_table mt20 mb10 ml5">
<tr class="vtop">
<td><img class="block32 ml10" src="/ono/osr/images/icons/crystal/32x32/ono/help.png" alt=""></td>
<td><div class="lh125 col9 italic">$txts[19] $txts[20]</div></td>
</tr>
</table>
~;

}

if ($vars{'output_paper'}) {

my $PRINT_FORMAT .= qq~<tr>
<td></td>
<td>~;

$PRINT_FORMAT .= ONO::Lib::PDF::ToolBox->format("app_input_paper_format",$BLK_ref,$vars_ref);

$PRINT_FORMAT .= qq~ </td>
</tr>
~;

$BLK{'blackwhite'} = $txts[10];
$BLK{'uniquecopies'} = $txts[11];
$BLK{'item_numbers'} = $txts[22];

foreach my $opt (

"t:app_input_print_options_title:title",
"o:app_input_print_options_code:code",
"m:app_input_print_options_name:name",
"d:app_input_print_options_auto_date:print_date",
"f:app_input_print_options_format:format",
"n:app_input_print_options_unique_copies:uniquecopies",
"b:app_input_print_options_blackwhite:blackwhite",
"c:app_input_print_options_corrections:inc_corrections",
"i:app_input_print_options_item_numbers:item_numbers",
"g:app_input_print_options_design:design",
"a:app_input_print_options_auto_eval:inc_self_eval",

) {

my @op = split(/:/,$opt);

if ($op[0] =~ /(t|o|m|n|f|g)/) {

if ($op[0] eq "t" && $switches !~ /Q/) {

$PRINT_OPTS .= qq~<tr>
<td class="tar">$BLK{$op[2]}:</td>
<td><input type="text" name="$op[1]" value="$vars{'app_input_print_options_title'}" style="width:320px" maxlength="16" onclick="this.select();"></td>
</tr>
~;

}

if ($op[0] eq "o" && $switches !~ /Q/) {

$PRINT_OPTS .= qq~<tr>
<td class="tar">$BLK{$op[2]}:</td>
<td><input type="text" name="$op[1]" value="$vars{'app_input_print_options_code'}" style="width:50px" maxlength="4" onclick="this.select();"></td>
</tr>
~;

}

if ($op[0] eq "m" && $switches !~ /Q/) {

$PRINT_OPTS .= qq~<tr>
<td class="tar">$BLK{$op[2]}:</td>
<td><input type="text" name="$op[1]" value="$vars{'app_input_print_options_name'}" style="width:320px" maxlength="16" onclick="this.select();"></td>
</tr>
~;

}

if ($op[0] eq "f") {

$PRINT_OPTS .= $PRINT_FORMAT;

}

if ($op[0] eq "n" && $switches !~ /U/) {

$PRINT_OPTS .= qq~<tr>
<td><input type="text" name="$op[1]" value="1" style="float:right;text-align:right;width:16px" maxlength="2" onclick="this.select();"></td>
<td>$BLK{$op[2]}</td>
</tr>
~;

}

if ($op[0] eq "g") {

$PRINT_OPTS .= &print_design("",$op[1],$lang,$BLK_ref,$switches);

}

} else {

my $OP0 = uc $op[0];
my $chk;
if ($switches =~ /$OP0/) {
$chk++;
}

my $SWITCH = ONO::Lib::UI::Check->switch($op[1],$chk,"r");

if ($op[0] =~ /^(b|c|d|a|i)$/ && $switches =~ /$op[0]/) {

if ($op[0] eq "i") {

my $RENUM = ONO::FW::Apps::Core::Graphics->pdf_draw_item_number_html_example_mini();

$PRINT_OPTS .= qq~<tr>
<td>$SWITCH</td>
<td class="p0"><table class="default_table"><tr class="vtop"><td>$BLK{$op[2]}</td>$RENUM</tr></table></td>
</tr>
~;

} else {

$PRINT_OPTS .= qq~<tr>
<td>$SWITCH</td>
<td>$BLK{$op[2]}</td>
</tr>
~;

}

if ($op[0] eq "c" && $vars{'output_paper_save'}) {

my $SWITCH = ONO::Lib::UI::Check->switch("output_paper_save_split",1,"mr");

$PRINT_OPTS .= qq~<tr>
<td></td>
<td class="p0">
<table class="default_table">
<tr>
<td>$SWITCH</td>
<td class="small col6">$txts[15]</td>
</tr>
</table>
</td>
</tr>
~;

}

}

}

}

if ($PRINT_OPTS) {

if ($vars{'output_paper_add_button'} || $vars{'output_paper_save'}) {
$BLK{'print_options'} = $BLK{'options'};
}
my $ICON = "/ono/osr/images/icons/crystal/32x32/ono/print.png";
my $hide = " hide";
if ($vars{'output_paper_save'}) {
$ICON = "/ono/osr/images/icons/crystal/32x32/actions/filesave.png";
# $hide = "";
$BLK{'Print_options'} = $BLK{'Options'};
$BLK{'ok'} = "$BLK{'continue'}...";
}

$PRINT_OPTS = qq~<div id="app_print_options_box" class="abs$hide" style="top:20px;left:20px;z-index:999">
<div class="box_fabric">
<table class="default_table">
<tr>
<td><img class="block24 mb5" src="$ICON" style="margin-right:3px" alt=""></td>
<td><h4 class="col6">$BLK{'Print_options'}</h4></td>
</tr>
</table>
<div class="box_paper">
<table class="default_table">
$PRINT_OPTS
<tr>
<td></td>
<td>
<a href="javascript:void(0);" onclick="onojs_hide('app_print_options_box');onojs_block('app_print_options_button');"
class="button_green">$BLK{'ok'}</a>
</td>
</tr>
</table>
</div>
</div>
</div>
~;

if (!$vars{'login_required'}) {
$PRINT_OPTS .= qq~<a href="javascript:void(0);" id="app_print_options_button" onclick="onojs_block('app_print_options_box');onojs_hide('app_print_options_button');"
class="button mb10">$BLK{'print_options'}...</a>
~;

if ($switches =~ /K/) {

$PRINT_OPTS .= qq~<div class="inline"><table class="default_table mt2 ml5">~;
$PRINT_OPTS .= ONO::FW::Apps::ToolBox->conf_input("resulthints", $BLK_ref,\%vars,"","","ai");
$PRINT_OPTS .= qq~</table></div>~;

}

}

}

}

if ($vars{'output_selected'} && !$vars{'output_save_now'} && !$vars{'login_required'} && !$vars{'output_web_exercise_autostart'}) {
$RELOAD = qq~<div id="app_input_reload_icon" class="fr trans50" style="padding:7px 2px 0px 0px"
onmouseover = "onojs_class('app_input_reload_icon','fr');"
onmouseout = "onojs_class('app_input_reload_icon','fr trans50');">
<a href="$action_url">
<img class="block16" src="/ono/osr/images/icons/ono/32x32/reload.png" alt="">
</a>
</div>
~;
}

if (!$vars{'exercise'} && !$vars{'output_paper'} && !$vars{'output_web'} && !$vars{'output_load'} && !$vars{'output_save'} && !$vars{'output_save_now'}) { # && !$vars{'output_selected'}) {

my $STYLE;
if ($lang eq "fr") {
$STYLE = "padding:3px 4px 3px 4px;margin-right:2px";
}
if ($lang eq "lu") {
$STYLE = "padding:3px 7px 3px 7px;margin-right:2px";
}

if ($switches =~ /l/) {
$OUTPUT_LOADSAVE .= qq~<td class="nowrap">
<a href="/exercises/?app=$app" class="button button_small mt5" style="$STYLE" target="_parent">$txts[0]</a>
</td>
~;
}
if ($switches =~ /s/) {
$OUTPUT_LOADSAVE .= qq~<td class="nowrap">
<input type="submit" name="output_save" value="$txts[1]..." class="button button_small mt5" style="$STYLE">
</td>
~;
}
if ($switches =~ /u/) {
$OUTPUT_LOADSAVE .= qq~<td class="nowrap">
<input type="submit" name="output_paper_save" value="$BLK{'save'} (PDF)" class="button button_small mt5" style="$STYLE">
</td>
~;
}

if ($OUTPUT_LOADSAVE) {

$OUTPUT_LOADSAVE = qq~<div id="app_input_loadsave_div" class="trans50">
<table class="wide_table"
onmouseover = "onojs_class('app_input_loadsave_div','');"
onmouseout = "onojs_class('app_input_loadsave_div','trans50');">
<tr>
<td><img class="block24 mt5" src="/ono/osr/images/icons/crystal/32x32/actions/filesave.png" style="margin-right:3px" alt=""></td>
$OUTPUT_LOADSAVE
<td class="w100"></td>
</tr>
</table>
</div>
~;
}
}

if (!$OUTPUT_LOADSAVE) {

# the following crazy table code ensures that the box won't collapse...
# don't understand why this works, but it works, so leave it as it is:

$OUTPUT_LOADSAVE = qq~<table class="wide_table"><tr><td></td><td class="w100"></td></tr></table>~;
}

if ($vars{'output_web_exercise_autostart'}) {

if ($vars{'exercise_flags'} !~ /L/ || $vars{'username'}) {

$BUTTONS = qq~<div class="inline auto" style="min-width:360px">
<div class="xlarge mb10 green center">$txts[17]</div>
<input type="submit" name="output_web" value="$BLK{'Start'}!" class="button_green button_big" style="width:100%;font-weight:bold;font-size:24px">
<input type="hidden" name="app_input_number_of_questions" value="$vars{'app_input_number_of_questions'}">
<input type="hidden" name="output_web_question_number" value="1">
</div>
<div class="p10"></div>
~;

}

# <script>
# document.forms[0].submit();
# </script>

}

if (!$vars{'output_add'}) {
$vars{'output_selected'}++;
}

if ($vars{'app_conf_box_buttons_below'}) {
$vars{'app_conf_box_buttons_below'} = qq~<tr><td></td><td><div class="rel" style="top:-10px">$vars{'app_conf_box_buttons_below'}</div></td></tr>~;
}

my $ABS = "top:2px";
if ($switches =~ /T/) {
$ABS = "top:10px";
}
if ($switches =~ /L/) {
$ABS .= ";left:10px";
}

my @errs = ONO::Lib::Web::Client->client_error_msgs($lang);

my $MAXWIDTH = 420;
if ($switches =~ /F/ && $vars{'app_input_folder'}) {
$MAXWIDTH = 800;
}
if ($switches =~ /W/ && $vars{'app_conf_box_maxwidth'}) {
$MAXWIDTH = $vars{'app_conf_box_maxwidth'};
}

my $CONF_BOX_TITLE = &conf_box_title("",$TITLE_ICON,$TITLE,$vars{'app_conf_box_color'});

if ($vars{'exercise'}) {
my $EX_URL = ONO::IO->http_domain_base()."/exercise/$vars{'exercise'}/";
my $FILE = ONO::Ext::Morzino::ToolBox->qr_make($EX_URL);
my $IMG = ONO::Ext::Morzino::ToolBox->qr_image_td($FILE,"pr",ONO::IO->base(),"p");
$OUTPUT_LOADSAVE .= qq~<table class="wide_table">
<tr>
$IMG
<td class="w100"><input type="text" name="exercise_sharing_id" value="$EX_URL" class="w98" onclick="this.select();"></td>
</tr>
</table>
~;
}

# check if there's a backup exercise

my $STORED;

my $anonymous;

my $DIR = &varstoredir("",$vars{'username'},$vars{'virclass'},$anonymous);

if ($DIR && !$vars{'output_web'} && !$vars{'output_paper'} && !$vars{'output_save'}) {

my (@files,$found);

foreach my $time (ONO::IO->dir($DIR)) {
if (length $time == 10) {
if ($time < (time()-(60*60*24*31))) {
ONO::IO->rmdir("$DIR/$time");
} else {
my $files;
foreach my $file (ONO::IO->dir("$DIR/$time","","","time")) {
if ($file =~ /^(.*?)_(.*?)\.txt$/) {
$files++;
if ($files > 1) {
ONO::IO->rm("$DIR/$time/$file");
} else {
$file =~ s~\.txt$~~;
@files = (@files,"$time\_$file");
$found = "$DIR/$time/$file";
}
}
}
if (!$files) {
ONO::IO->rmdir("$DIR/$time");
}
}
}
}

if ($found) {

my @txt = ONO::FW::Apps::Core::LangKit->conf_box_2($lang);

my $AUTHINFO;
if ($vars{'username'}) {
$AUTHINFO = qq~, $BLK{'by'} $BLK{'user'} '$vars{'username'}'~;
}

my $num = @files;
my $CONTINUE = qq~<div class="inline mt10"><a href="$action_url&varstoreaction=load_$files[0]" class="button_green button_big">$txt[3]</a></div>~;
my @fp = split(/_/,$files[0]);
my $time = ONO::Lib::DateTime::ToolBox->get($fp[0],"","iz",$lang);
my $INFO = " ($BLK{'created'} $time$AUTHINFO).";

if ($num > 1) {
$CONTINUE = "";
my $count;
foreach my $file (reverse sort @files) {
$count++;
if ($count < 4) {
my @fp = split(/_/,$file);
my $time = ONO::Lib::DateTime::ToolBox->get($fp[0],"","iz",$lang);
$CONTINUE .= qq~<div class="inline mt10"><a href="$action_url&varstoreaction=load_$file" class="button_green button_big">$BLK{'resume'} ($time)</a></div>~;
}
}
$INFO = "$AUTHINFO.";
$txt[5] .= " ($BLK{'all'})";
}

$STORED .= qq~<div id="varstore_box" class="abs" style="top:20px;left:20px;z-index:999">
<div class="box_black">
<a href="javascript:void(0);" onclick="onojs_hide('varstore_box');"><img class="close" alt="close button"></a>
<h3 class="cole">$txt[0]</h3>
<div class="box_fabric">
<div class="mb10 large">$txt[1]$INFO</div>
<div class="mb10 large">$txt[2]</div>
$CONTINUE
<div class="inline mt10"><a href="javascript:void(0);" onclick="onojs_hide('varstore_box');" class="button_yellow button_big">$txt[4]</a></div>
<div class="inline mt10"><a href="$action_url&varstoreaction=delete" class="button_red button_big">$txt[5]</a></div>
</div>
</div>
</div>
~;
}
}

my ($VIRCLASS,$test_virclass_user);

# if (ONO::IO->devstation && !$vars{'virclass_user'} && $vars{'output_web'} && !$vars{'output_paper'}) {
# $test_virclass_user++;
# }

if ((!$vars{'username'} && !$vars{'virclass_user'} && $vars{'virclass'} && $vars{'output_web'} && !$vars{'output_paper'}) || $test_virclass_user) {
if ($vars{'virclass'} =~ /^(.*?):(.*?)$/) {
my $virclass_id = $1;
my $virclass_comp = $2;

$virclass_id =~ s~[^0-9]~~g;

my $STUDENTS;

foreach my $line (ONO::DB->select($db,"${community}_school_virclass_relationships","virclass = '$virclass_id' AND status = '1' AND type = 'student'","realname")) {
my @row = ONO::DB->readcols($line);
if (!$row[5]) {
$row[5] = $row[1];
}
$row[5] = ucfirst $row[5];

$STUDENTS .= qq~<div class="inline"><a href="javascript:void(0);" onclick="ono_fw_apps_exec_virclass_auth_userload('$row[1]','$row[5]');" class="button_green button_big mb10">$row[5]</a></div>~;

#ono_fw_apps_exec_virclass_auth_user
#parent.document.body.style.backgroundColor = "red";
}

if ($STUDENTS) {

my $WIN_URL = $action_url;
$WIN_URL =~ s~\&\;~\&~g;

foreach my $key (keys %vars) {
if ($key =~ /^app_input_/) {
$WIN_URL .= qq~&$key=$vars{$key}~;
}
}

$VIRCLASS .= qq~<div id="virclass_box" class="abs" style="top:20px;left:20px;z-index:999">
<div id="virclass_box_1" class="box_black p20">
<table class="default_table">
<tr>
<td class="p10"><a href="javascript:void(0);" onclick="onojs_hide('virclass_box_1');onojs_block('virclass_box_2');" class="button_green button_big">$BLK{'Student'}...</a></td>
<td class="p10"><a href="$action_url&virclass_user=anonymous" class="button_orange button_big">$BLK{'Anonymous'}</a></td>
<td class="p10"><a href="$action_url&virclass_user=anonymous"><img class="close" alt="close button"></a></td>
</tr>
</table>
</div>
<div id="virclass_box_2" class="box_black hide">
<a href="$action_url&virclass_user=anonymous"><img class="close" alt="close button"></a>
<h3 class="cole">$BLK{'Student'}...</h3>
<div class="box_fabric">
<div style="min-width:360px;max-height:360px;overflow-x:hidden;overflow-y:scroll">
<div class="inline w100"><a href="$action_url&virclass_user=anonymous" class="button_orange button_big mb10">$BLK{'Anonymous'} ($BLK{'no_name'})</a></div>
$STUDENTS
</div>
</div>
</div>
</div>
<script>
function ono_fw_apps_exec_virclass_auth_userload(username,realname) {
if (parent.document.getElementById('ono_fw_apps_exec_virclass_auth_user')) {
parent.document.getElementById('ono_fw_apps_exec_virclass_auth_user').style.display='table-cell';
parent.document.getElementById('ono_fw_apps_exec_virclass_auth_username').innerHTML=realname;
}
window.location='$WIN_URL&virclass_user='+username;
}
</script>
~;

}

}
}

my $BOX = "box_fabric";
my $STYLE = "padding-bottom:0px";
if ($vars{'app_conf_box_color'}) {
$BOX = "box_$vars{'app_conf_box_color'}";
}
if ($vars{'app_conf_box_inner_style'}) {
$STYLE = $vars{'app_conf_box_inner_style'};
}

my ($FORM1,$FORM2);

if ($vars{'output_login_required'}) {

my @txt = (
"Login required",
"You need to be logged in to access this web application.",
);

if ($lang eq "de" || $lang eq "lu") {
@txt = (
"Login erforderlich",
"Du musst angemeldet sein, um auf diese Webanwendung zugreifen zu können.",
);
}
if ($lang eq "fr") {
@txt = (
"Connexion requise",
"Vous devez être connecté pour accéder à cette application web.",
);
}

$BOX .= " trans70";

my $LOGIN = ONO::IO->http_domain_base()."/login/";

$OVERLAY = qq~<div class="box_blue abs" style="top:125px;left:100px;width:325px;z-index:999">
<h3 class="cole">$txt[0]</h3>
<div class="box_paper">
<div class="large lightred">$txt[1]</div>
<div class="inline"><a href="$LOGIN" class="button_green button_big mt10" target="_parent">$BLK{'login'}</a></div>
</div>
</div>
~;

} else {

$FORM1 = qq~<$form id="output_form_id">
<input type="hidden" name="output_selected" value="$vars{'output_selected'}">
<input type="hidden" name="exercise" value="$vars{'exercise'}">
<input type="hidden" name="exercise_id" value="$vars{'exercise_id'}">
$input
~;
$FORM2 = qq~</form>~;

}

return qq~$FORM1
<div id="$vars{'app_conf_box_id'}" class="$BOX abs" style="$ABS;max-width:${MAXWIDTH}px;padding:5px 10px 5px 10px">
$CONF_BOX_TITLE
<div class="box_paper p5_720" style="$STYLE">
<div id="morzino_apps_core_conf_jserror" class="inline w100">
<div class="mb5 lightred bold">$errs[0]</div>
<div class="mb5 col6">$errs[1]</div>
<div class="mb10 col6">$errs[2]</div>
</div>
<div id="morzino_apps_core_conf_box" class="inline w100 hide">
$STORED
$VIRCLASS
<table class="wide_table">
$CONF
<tr>
<td>$RELOAD</td>
<td class="w100"><div class="mt5">$BUTTONS$PRINT_OPTS</div></td>
</tr>
$vars{'app_conf_box_buttons_below'}
</table>
</div>
</div>
<div id="morzino_apps_core_conf_loadsave" class="hide">$OUTPUT_LOADSAVE</div>
</div>
$OVERLAY
$FORM2
<script>
onojs_hide('morzino_apps_core_conf_jserror');onojs_block('morzino_apps_core_conf_box');onojs_block('morzino_apps_core_conf_loadsave');
</script>
~;

}

}

sub conf_box_title {

#: Generate the configuration box title.

my $COL = "col6";
if ($_[3] eq "black") {
$COL = "cole";
}

return qq~<table class="default_table mb5">
<tr class="vtop">
<td><img class="block24" src="/ono/osr/images/icons/crystal/32x32/$_[1].png" style="margin-right:3px" alt=""></td>
<td><h3 class="m0 $COL">$_[2]</h3></td>
</tr>
</table>
~;

}

###################################################################
# configuration input lines
###################################################################

sub conf_input {

#: Deprecated here, moved to ONO_FW_Apps_ToolBox.

my (
$self,
$type,
$BLK_ref,
$vars_ref,
$switches,
@data,
) = @_;

ONO::FW::Apps::ToolBox->conf_input($type,$BLK_ref,$vars_ref,$switches,@data);

}

###################################################################
# useful stuff
###################################################################

sub lang_check {

#: Check lang codes.

my (
$self,
@langs
) = @_;

for (my $i = 0; $i < 2; $i++) {
if ($langs[$i] ne "img") {
$langs[$i] = lc substr($langs[$i],0,2);
}
$langs[$i] =~ s~[^a-z]~~g;
}

return ($langs[0],$langs[1]);

}

sub lang_check_unique {

#: Check and make sure lang codes are unique.

my (
$self,
@langs
) = @_;

# if languages are the same, then use fallback language as second language

if ($langs[0] eq $langs[1]) {
$langs[1] = $langs[2];
}

# if still unique, then flush languages

if ($langs[0] eq $langs[1]) {

return ('','');

} else {

return ($langs[0],$langs[1]);

}

}

sub range_check {

#: Check number range - deprecated here, moved to ONO_FW_Apps_Core_Math.

my (
$self,
$max_from,
$max_to,
$from,
$to,
$negative,
$numsys,
) = @_;

return ONO::FW::Apps::Core::Math->range_check(
$max_from,
$max_to,
$from,
$to,
$negative,
$numsys,
);
}

sub get_operations {

#: Deprecated here, moved to ONO_FW_Apps_Core_Math.

return ONO::FW::Apps::Core::Math->get_operations($_[1]);

}

sub operation_symbol {

#: Deprecated here, moved to ONO_FW_Apps_Core_Math.
#:
#: Switches:
#:
#: -c colorize
#: -p print / pdf mode
#: -s use slash as division symbol
#: -x executable (simple code)

return ONO::FW::Apps::Core::Math->operation_symbol($_[1],$_[2]);

}

sub random_operation {

#: Select random operation.

my $num = @_;

return $_[int(rand($num-1))+1];

}

sub random_number {

#: Deprecated here, moved to ONO_FW_Apps_Core_Math.

my (
$self,
$from,
$to,
$min,
$max,
$vars_ref,
) = @_;

return ONO::FW::Apps::Core::Math->random_number(
$from,
$to,
$min,
$max,
$vars_ref,
);

}

sub input_vars {

my (
$self,
$vars_ref,
$switches,
) = @_;

#: Deprecated here, moved to ONO_FW_Apps_Core_ToolBox.
#:
#: Switches:
#:
#: -f first question is 1 as first step, not 2
#: -r reload app with same settings mode
#: -R include Report variables
#: -x incluce exercise code and ID (incompatible with -r)

return ONO::FW::Apps::Core::ToolBox->input_vars($vars_ref,$switches);

}

sub question_number {

return ONO::FW::Apps::Core::Question->question_number($_[1])

}

sub question_progress {

#: Deprecated here, moved to ONO_FW_Apps_Core_Question.

my (
$self,
$total,
$question,
$MORE,
$switches,
) = @_;

return ONO::FW::Apps::Core::Question->question_progress(
$total,
$question,
$MORE,
$switches,
);

}

sub question_progress_done {

#: Deprecated here, moved to ONO_FW_Apps_Core_Question.

return ONO::FW::Apps::Core::Question->question_progress_done($_[1],$_[2]);

}

sub question_progress_done_msg {

#: Deprecated here, moved to ONO_FW_Apps_Core_Question.

my (
$self,
$app,
$db,
$community,
$form,
$action_url,
$questions,
$mistakes,
$lang,
$BLK_ref,
$vars_ref,
$switches,
) = @_;

return ONO::FW::Apps::Core::Question->question_progress_done_msg(
$app,
$db,
$community,
$form,
$action_url,
$questions,
$mistakes,
$lang,
$BLK_ref,
$vars_ref,
$switches,
);

}

sub unique_copies {

#: Logic to allow the generation of multiple page copies.

my (
$self,
$num,
$multiplexer,
) = @_;

if ($num < 1 || $num > 99) {
$num = 1;
}
if ($multiplexer < 1 || $multiplexer > 99) {
$multiplexer = 1;
}

my (@copies,$counter);

for (my $i = 1; $i < $multiplexer+1; $i++) {
for (my $j = 1; $j < $num+1; $j++) {
$counter++;
@copies = (@copies,$counter);
}
}

return @copies;

}

sub unique_copies_info {

#: Logic to allow the generation of multiple page copies.

my (
$self,
$canvas,
$copy,
$vars_ref,
) = @_;
my %vars = %$vars_ref;

if ($vars{'app_input_print_options_unique_copies'} > 1) {
ONO::Lib::PDF::Draw->text($canvas,170,-5,"$copy / $vars{'app_input_print_options_unique_copies'}","right");
}

}

sub check_rightwrong {

#: Deprecated here, moved to ONO_FW_Apps_Core_Check.

my (
$self,
$is_wrong,
$BLK_ref,
) = @_;

return ONO::FW::Apps::Core::Check->check_rightwrong($is_wrong,$BLK_ref);

}

sub check_single {

#: Deprecated here, moved to ONO_FW_Apps_Core_Check.

shift @_;

return ONO::FW::Apps::Core::Check->check_single(@_);

}

sub check_multi {

#: Deprecated here, moved to ONO_FW_Apps_Core_Check.

my (
$self,
$BLK_ref,
$remaining,
$page,
$pages,
$switches,
$vars_ref,
) = @_;

return ONO::FW::Apps::Core::Check->check_multi(
$BLK_ref,
$remaining,
$page,
$pages,
$switches,
$vars_ref,
);

}

sub clean_answer_math {

#: Clean up math / number inputs.

my $answer = $_[1];

$answer =~ s~(\n|\r|\t| )~~g;
$answer =~ s~\,~\.~g;
$answer = uc $answer;
if ($_[2] =~ /r/) {
$answer =~ s~[^0-9\.\-\I\V\X\L\C\D\M]~~gi;
} else {
$answer =~ s~[^0-9\.\-]~~gi;
}

return $answer;

}

sub round_up {

#: Deprecated here, moved to ONO_FW_Apps_Core_Math.

my (
$self,
$num,
$vars_ref
) = @_;

return ONO::FW::Apps::Core::Math->round_up($num,$vars_ref);

}

sub numsys {

#: Translate number systems (decimal, roman, hex).

my (
$self,
$num1,
$num2,
$num3,
$numsys,
) = @_;

my @num = ($num1,$num2,$num3);

for (my $i = 0; $i < 3; $i++) {

if ($numsys eq "roman") {
$num[$i] = ONO::Lib::Data::Numbers::Roman->get($num[$i],"rn");
}

if ($numsys eq "hex") {
$num[$i] = ONO::Lib::Data::Numbers::Hexa->get($num[$i]);
}

}

return @num;

}

sub number_length {

#: Detect the string length of a number.

my (
$self,
$max,
$comma,
) = @_;

if ($comma > 0) {
$comma++;
}

return (length $max) + $comma;

}

sub detect_local {

#: Detect where we are located (using domain).

my $local;

if ($ENV{'SERVER_NAME'} =~ /\.(com|net|org)$/) {
$local = "us";
}
if ($ENV{'SERVER_NAME'} =~ /\.(at|ch|cz|de|dk|es|eu|fi|fr|gr|hr|it|ie|nl|no|pt|se|sm|ua|uk)$/) {
$local = "eu";
}
if ($_[1] =~ /^(de|fr|lu)$/) {
$local = "eu";
}
if (ONO::IO->devstation) {
$local = "eu";
}

return $local;

}

sub local_comma_delimiter {

#: Set comma delimiter (US/EU).

my (
$self,
$local,
$vars_ref,
) = @_;

my %vars;
if ($vars_ref) {
%vars = %$vars_ref;
}

my ($num_comma,$num_delimiter) = (".",",");

if ($local eq "eu") {
# ($num_comma,$num_delimiter) = (",","'");
($num_comma,$num_delimiter) = (",","");
if ($vars{'output_web'}) {
# ($num_comma,$num_delimiter) = (",",qq~<span class="col9">’</span>~);
($num_comma,$num_delimiter) = (",",qq~<span class="col9">˙</span>~);
}
}

return ($num_comma,$num_delimiter);

}

sub make_human_readable {

#: Deprecated here, moved to ONO_FW_Apps_Core_Math.

my (
$self,
$num,
$num_comma,
$num_delimiter,
) = @_;

return ONO::FW::Apps::Core::Math->make_human_readable($num,$num_comma,$num_delimiter);

}

sub fix_fp_rounding {

#: Deprecated here, moved to ONO_FW_Apps_Core_Math.

my $num = ONO::FW::Apps::Core::Math->fix_fp_rounding($_[1]);

return $num;

}

sub float_to_decimal {

#: Deprecated here, moved to ONO_FW_Apps_Core_Math.

my $num = ONO::FW::Apps::Core::Math->float_to_decimal($_[1]);

return $num;

}

sub html_exponent {

#: Exponent to HTML.

my $num = $_[1];

$num =~ s~\^2~<span class="sup">2</span>~;
$num =~ s~\^3~<span class="sup">3</span>~;

return $num;

}

sub comma_limit {

my (
$self,
$num,
$limit,
) = @_;

#: Deprecated here, moved to ONO_FW_Apps_Core_Math.

my $num = ONO::FW::Apps::Core::Math->comma_limit($num,$limit);

return $num;

}

sub multi_page_logic {

my (
$self,
$page,
$vars_ref,
$force_questions_per_page,
$switches,
) = @_;

#: Mulit-page logic for online exercises.
#:
#: Switches:
#:
#: -p page can't be zero
#: -P pages can't be zero

my %vars = %$vars_ref;

my $stats_switches;
my $questions_per_page = $vars{'app_input_number_of_questions'};
my $default_questions_per_page = 20;
my $pages;

if ($force_questions_per_page) {
$default_questions_per_page = $force_questions_per_page;
}

if ($questions_per_page > $default_questions_per_page) {

$questions_per_page = $default_questions_per_page;
$page++;
if ($vars{'output_web_page'}) {
$page = $vars{'output_web_page'};
}
if ($vars{'output_web_next_page'}) {
$page++;
$vars{'output_web_page'} = $page;
}
$pages = int(($vars{'app_input_number_of_questions'}-1)/$default_questions_per_page)+1;
$stats_switches .= "p";

}

if ($vars{'output_web_page'} && $vars{'output_web_page'} == $pages && $vars{'app_input_number_of_questions'} > $default_questions_per_page) {

$questions_per_page = $vars{'app_input_number_of_questions'};
my $whilecounter;
while ($questions_per_page > $default_questions_per_page && $whilecounter < 256) {
$whilecounter++;
$questions_per_page = $questions_per_page - $default_questions_per_page;
}

}

if ($switches =~ /p/ && $page < 1) {
$page = 1;
}
if ($switches =~ /P/ && $pages < 1) {
$pages = 1;
}

return ($stats_switches,$questions_per_page,$page,$pages);

}

sub multi_frame_start {

#: Logic for splitting am exercise into two rows.

if ($_[1]) {

return "";

} else {

my $width = "w50";
if ($_[2]) {
$width = $_[2];
}

return qq~<div class="p10"><div class="inline w100 bg_fabric"><div class="$width fl w100_900 fn_900"><table class="wide_table bt bb">~;

}

}

sub multi_frame_split {

#: Logic for splitting am exercise into two rows.

my $width = "w50";
if ($_[1]) {
$width = $_[1];
}

return qq~</table></div><div class="$width fl w100_900 fn_900"><table class="wide_table bt bb">~;

}

sub multi_frame_end {

#: Logic for splitting am exercise into two rows.

if (!$_[1] && $_[2]) {

return qq~</table></div></div></div>~;

} else {

return "";

}

}

sub generate_add {

#: Deprecated here, moved to ONO_FW_Apps_Core_Math.

my (
$self,
$i,
$num1,
$num2,
$op,
$res,
$cache1,
$cache2,
$vars_ref,
$force_flush,
) = @_;

my ($num1,$num2,$res,$cache1,$cache2,$DEBUG) = ONO::FW::Apps::Core::Math->generate_add(
$i,
$num1,
$num2,
$op,
$res,
$cache1,
$cache2,
$vars_ref,
$force_flush,
);

return ($num1,$num2,$res,$cache1,$cache2,$DEBUG);

}

sub generate_sub {

#: Deprecated here, moved to ONO_FW_Apps_Core_Math.

my (
$self,
$i,
$num1,
$num2,
$op,
$res,
$cache1,
$cache2,
$vars_ref,
$force_flush,
) = @_;

my ($num1,$num2,$res,$cache1,$cache2,$DEBUG) = ONO::FW::Apps::Core::Math->generate_sub(
$i,
$num1,
$num2,
$op,
$res,
$cache1,
$cache2,
$vars_ref,
$force_flush,
);

return ($num1,$num2,$res,$cache1,$cache2,$DEBUG);

}

sub generate_muldiv {

#: Deprecated here, moved to ONO_FW_Apps_Core_Math.

my (
$self,
$i,
$num1,
$num2,
$op,
$res,
$cache1,
$cache2,
$vars_ref,
$force_flush,
) = @_;

my ($num1,$num2,$res,$cache1,$cache2,$DEBUG) = ONO::FW::Apps::Core::Math->generate_muldiv(
$i,
$num1,
$num2,
$op,
$res,
$cache1,
$cache2,
$vars_ref,
$force_flush,
);

return ($num1,$num2,$res,$cache1,$cache2,$DEBUG);

}

###################################################################
# OLD STUFF BELOW...
###################################################################

sub win {

my (
$self,
$form,
$FORM,
$BLK_ref,
$switches,
) = @_;

#: Configuration window generator.
#:
#: Switches:
#:
#: -o online
#: -p print

my %BLK = %$BLK_ref;
my $BUTTONS;

if ($switches =~ /o/) {
$BUTTONS .= qq~<input type="submit" name="output_web" value="$BLK{'online_training'}" class="button_green">~;
}

if ($switches =~ /p/) {
# not implemented yet
}

return qq~<div class="box_fabric_white_light" style="width:500px;margin-left:10px">
<h2 style="margin-bottom:10px">$BLK{'Configure_exercise'}:</h2>
<div class="box_paper">
<$form>
$FORM
<div class="mt10">
<div class="inline auto" id="button_submit">$BUTTONS</div>
</div>
</form>
</div>
</div>
~;

}

###################################################################
# info pics
###################################################################

sub infopics_simple {

my @IMG2 = &infopics_core(@_);

#: Infopics generator.
#: This version does NOT set any sizes, the result may need to be fitted in a div using width and height!

return ONO::Lib::UI::Image->collection("0:0:0:0:0",@IMG2);

}

sub infopics {

#: Infopics generator.

my @IMG2 = &infopics_core(@_);

return qq~<div class="hide600">~.ONO::Lib::UI::Image->collection("400:420:60::10:abs",@IMG2)."</div>";

}

sub infopics_core {

#: Infopics generator.

my @IMG = @_;
my @IMG2;

foreach my $img (@IMG) {

my @ip = split(/:/,$img);

if ($ip[0] =~ /^(screen|sheet|image)$/) {

my $w = $ip[1];
my $h = int($ip[1]/210*297);
my $th = int($ip[1]/7.6);
my $b;
my $sw = "st";
$ip[5] = "/images/morzino/apps/$ip[5]";

if ($ip[0] eq "screen") {

$w = $ip[1];
$h = int($ip[1]/1280*720);
$th = int($ip[1]/11.5);
my $img = "topbar_screen_morzino.jpg";
if ($ENV{'SERVER_NAME'} =~ /oli/) {
$img = "topbar_screen_oli_lu.jpg";
}
if (&variation eq "education.lu") {
$img = "topbar_screen_oli_education.jpg";
}
$ip[5] .= ";/images/morzino/apps/$img;$th";
}

if ($ip[0] eq "sheet") {
# $b = 5;
my $img = "topbar_sheet_morzino.jpg";
if ($ENV{'SERVER_NAME'} =~ /oli/) {
$img = "topbar_sheet_oli_lu.jpg";
}
if (&variation eq "education.lu") {
$img = "topbar_sheet_oli_education.jpg";
}
$ip[5] .= ";/images/morzino/apps/$img;$th";
}

if ($ip[0] eq "image") {
$w = $ip[1];
$h = $ip[1];
if ($ip[1] =~ /^(.*?)x(.*?)$/) {
$w = $1;
$h = $2;
}
$sw = "";
}

@IMG2 = (@IMG2,"img:$ip[2]:$ip[3]:$ip[5]:$w:$h:$b:$ip[4]:$sw");

}

}

return @IMG2;

}

###################################################################
# generate subtitles
###################################################################

sub subtitles {

#: Deprecated here, moved to ONO_FW_Apps_Core_LangKit.

return ONO::FW::Apps::Core::LangKit->subtitles($_[1]);

}

###################################################################
# update now
###################################################################

sub now {

#: Deprecated.

}

###################################################################
# mkpdf
###################################################################

sub mkpdf {

#: Deprecated here, moved to ONO_FW_Apps_Core_Graphics.

my (
$self,
$BLK_ref,
$vars_ref,
$HTTP,
$BASE,
) = @_;

return ONO::FW::Apps::Core::Graphics->mkpdf(
$BLK_ref,
$vars_ref,
$HTTP,
$BASE,
);

}

###################################################################
# mkpdf
###################################################################

sub output_paper {

#: Deprecated here, moved to ONO_FW_Apps_Core_Graphics.

my (
$self,
$pdfkey,
$BLK_ref,
$vars_ref,
$HTTP,
$BASE,
$switches,
) = @_;

return ONO::FW::Apps::Core::Graphics->output_paper(
$pdfkey,
$BLK_ref,
$vars_ref,
$HTTP,
$BASE,
$switches,
);

}

sub output_paper_save {

#: Save a PDF file.

my (
$self,
$pdfkey,
$BLK_ref,
$vars_ref,
$HTTP,
$BASE,
$yearmonmday,
) = @_;

my %vars = %$vars_ref;

if ($vars{'output_paper_save_exec'} || $vars{'output_paper_save_target_change'} || $vars{'output_paper_save_target_app_change'}) {

if ($vars{'output_paper_save_pdfkey'}) {
$pdfkey = $vars{'output_paper_save_pdfkey'};
}

return ONO::FW::Apps::Core::Save->output_paper_save($pdfkey,$BLK_ref,$vars_ref,$HTTP,$BASE,$yearmonmday);

} else {

return "";

}

}

###################################################################
# headers
###################################################################

sub headers_options {

#: PDF header helper.

my $BLK_ref = $_[1];
my $vars_ref = $_[2];

my %BLK = %$BLK_ref;
my %vars = %$vars_ref;

my ($RET,$OPS);

if ($vars{'app_input_range_from'} && $vars{'app_input_range_to'}) {
$RET .= "$BLK{'Numbers'} $vars{'app_input_range_from'} - $vars{'app_input_range_to'}";
}
foreach my $op ('add','sub','mul','div') {
if ($vars{"app_input_op_$op"}) {
$OPS .= qq~$BLK{"op_$op"}, ~;
}
}

if ($OPS) {
$OPS =~ s~, $~~;
if ($RET) {
$RET .= ", ";
}
$RET .= "$OPS";
}

return $RET;

}

sub headers {

my (
$self,
$vars_ref,
$format,
$switches
) = @_;

#: PDF header options.
#:
#: Switches:
#:
#: -c is correction sheet
#: -C alternative copyright
#: -E alternative copyright: evaluation
#: -N alternative copyright: notes
#: -X no copyright, no name, no date

my %vars = %$vars_ref;

my ($sub1,$sub2) = &subtitles("",\%vars);

my $done;

my $test;
if (ONO::IO->devstation) {
#$test = 2;
}

# special case: morzino

if (($ENV{'SERVER_NAME'} =~ /(morzino)/ || ONO::IO->devstation) && $switches !~ /(E|X)/) {
$switches .= "E";
}
if (($ENV{'SERVER_NAME'} =~ /(jamplifier)/ || ONO::IO->community() eq "music") && $switches !~ /(N|X)/) {
$switches .= "NX";
}

# designs

if ($vars{'ono_app_print_design'}) {
$vars{'app_input_print_options_design'} = $vars{'ono_app_print_design'};
}
if ($vars{'ono_app_print_design_corrections'}) {
$vars{'app_input_print_options_design_corrections'} = $vars{'ono_app_print_design_corrections'};
}

if ($vars{'app_input_print_options_design'} && ($switches !~ /c/ || $vars{'app_input_print_options_design_corrections'})) {

my $community = ONO::IO->community();

if (!$community) {
$community = "school";
}

ONO::Lib::PDF::ToolBox->design_print($community,$vars{'app_input_print_options_design'},$format);

}

# logo and cc


if ($format !~ /^q/) {

my ($top1,$top2,$top3,$width) = ONO::Lib::PDF::ToolBox->design_coords($format);

ONO::Lib::PDF::Draw->image("",16,$top1,20,20,"ono-data/school/pdf/logo_32.jpg",2,2);
if ($switches !~ /(C|E|N|X)/) {
ONO::Lib::PDF::Draw->image("",17.5,$top2,23,6,"ono-data/school/pdf/cc_logo.jpg");
}

}

# titles and subtitles

# if (($ENV{'SERVER_NAME'} =~ /oli\.lu/ || $test == 1) && &variation ne "education.lu") {
#
# $done++;
#
# ONO::FW::Apps::PDF->headers(
# \%vars,
# "oli.lu",
# $sub1,
# $sub2,
# "www.oli.lu",
# $format,
# $switches,
# );
#
# }

if ($format !~ /^q/) {

my $devmode;

# $devmode++;

if (ONO::IO->devstation && $devmode) {

$done++;

ONO::FW::Apps::PDF->headers(
\%vars,
"AppsDev",
"",
"Dev",
"DEV",
$format,
$switches,
);

} else {

if (ONO::Lib::Web::Domain->variation eq "morzino" || $test == 2) {

$done++;

my ($TITLE,$COPY) = ("Worksheet by Morzino.com","The Morzino Project - www.morzino.com");

if ($vars{'lang'} eq "de" || $vars{'app_input_paper_lang'} eq "de") {
($TITLE,$COPY) = ("Arbeitsblatt von Morzino.de","Das Morzino Projekt - www.morzino.de");
}

if ($vars{'lang'} eq "fr" || $vars{'app_input_paper_lang'} eq "fr") {
($TITLE,$COPY) = ("Fiche de travail par Morzino.fr","Le projet Morzino - www.morzino.fr");
}

ONO::FW::Apps::PDF->headers(
\%vars,
$TITLE,
"",
"$sub1 - $sub2",
$COPY,
$format,
$switches,
);

}

if (ONO::Lib::Web::Domain->variation eq "oli" || $test == 2) {

$done++;

my ($TITLE,$COPY) = ("Oli.lu","www.oli.lu");

ONO::FW::Apps::PDF->headers(
\%vars,
$TITLE,
"",
"$sub1 - $sub2",
$COPY,
$format,
$switches,
);

}

if (&variation eq "education.lu" || $test == 3) {

$done++;

ONO::FW::Apps::PDF->headers(
\%vars,
"oli.education.lu",
"",
"De Portail vun der Grondschoul",
"oli.education.lu",
$format,
$switches,
);

}

if (ONO::Lib::Web::Domain->variation eq "jamplifier") {

$done++;

my ($TITLE,$COPY) = ("","The Jamplifier Project - www.jamplifier.com");

ONO::FW::Apps::PDF->headers(
\%vars,
$TITLE,
"",
"",
$COPY,
$format,
$switches,
);

}

}

if (!$done) {

if ($ENV{'SERVER_NAME'} =~ /oli/) {

ONO::FW::Apps::PDF->headers(
\%vars,
"oli.lu",
"",
"$sub1 - $sub2",
"www.oli.lu",
$format,
$switches,
);

} else {

ONO::FW::Apps::PDF->headers(
\%vars,
"morzino.com",
"",
"$sub1 - $sub2",
"www.morzino.com",
$format,
$switches,
);

}

}

}

ONO::FW::Apps::PDF->specimen($vars{'output_canvas'},$vars_ref);

}

###################################################################
# stats
###################################################################

sub stats_multi_pages {

#: Deprecated here, moved to ONO_FW_Apps_Core_Stats.

my (
$self,
$questions,
$stat_correct,
$stat_wrong,
$page,
$pages,
$questions_per_page,
) = @_;

return ONO::FW::Apps::Core::Stats->stats_multi_pages(
$questions,
$stat_correct,
$stat_wrong,
$page,
$pages,
$questions_per_page,
)

}


sub stats_replace {

#: Deprecated here, moved to ONO_FW_Apps_Core_Stats.

my @data = @_;

return ONO::FW::Apps::Core::Stats->stats_replace(
$data[1],$data[2],$data[3],$data[4],$data[5],$data[6],$data[7],$data[8],$data[9]
);

}

sub stats {

#: Deprecated here, moved to ONO_FW_Apps_Core_Stats.

my (
$self,
$MORE,
$BLK_ref,
$switches,
) = @_;

return ONO::FW::Apps::Core::Stats->stats(
$MORE,
$BLK_ref,
$switches,
)

}

###################################################################
# info
###################################################################

sub info_display {

#: Info display.

return qq~<div class="hide900 italic fr p10 center" style="width:400px">$_[1]$_[2]</div>~;

}

sub info {

my (
$self,
$item,
$lang,
) = @_;

#: Get info for nfo display.

return ONO::FW::Apps::Core::LangKit->info($item,$lang);

}

###################################################################
# print options
###################################################################

sub print_corrections {

#: Print corrections helper.

my (
$self,
$file,
$template,
$format,
$vars_ref,
) = @_;

my %vars = %$vars_ref;

if ($vars{'output_paper'} && $vars{'app_input_print_options_corrections'}) {

if ($vars{'output_paper_save_split'}) {
ONO::FW::Apps::PDF->end();
ONO::FW::Apps::PDF->new($file,$template,$format);
} else {
ONO::FW::Apps::PDF->page($template,$format);
}

return 1;

} else {

return 0;

}

}

###################################################################
# print options
###################################################################

sub print_options {

#: Deprecated.

return "";


}

sub hint_script {

#: Deprecated.

return "";

}

sub hint_script_v2 {

#: Display online hints helper.

my (
$self,
$math1,
$math2,
$hints,
$TARGET,
) = @_;

if (!$math1) {
$math1 = "length/3";
}
if (!$math2) {
$math2 = "(length/2)+1";
}
if (!$TARGET) {
$TARGET = "'output_web_answer_'+id+'_id'";
}
if ($TARGET !~ /\'/) {
$TARGET = "'$TARGET'";
}

return qq~<input type="hidden" id="output_web_hints" name="output_web_hints" value="$hints">
<script>
function hint(id) {
var hints = document.getElementById('output_web_hints_'+id).value;
var length = (document.getElementById('output_web_correct_'+id).value).length;
if (hints < 3) {
document.getElementById('output_web_hints_'+id).value++;
var hint_count = document.getElementById('output_web_hints_counter_'+id).innerHTML;
hint_count++;
document.getElementById('output_web_hints_counter_'+id).innerHTML=hint_count;
var total = document.getElementById('output_web_hints').value;
total++;
document.getElementById('output_web_hints').value = total;
document.getElementById('output_web_total_hints').innerHTML = total;
}
if (hints == 0) {
onojs_setvalue($TARGET,(onojs_getvalue('output_web_correct_'+id)).substring(0,$math1));
}
if (hints == 1) {
onojs_setvalue($TARGET,(onojs_getvalue('output_web_correct_'+id)).substring(0,$math2));
}
if (hints == 2 || length == 2) {
onojs_setvalue($TARGET,onojs_getvalue('output_web_correct_'+id));
onojs_hide('output_web_hint_button_'+id);
onojs_block('output_web_hint_button_off_'+id);
}
}
</script>
~;
}

###################################################################
# var store (store exercise for later restart)
###################################################################

sub varstoreaction {

#: Store exercise for later restart logic.

my $vars_ref = $_[1];
my %vars = %$vars_ref;

if ($vars{'varstoreaction'} && ($vars{'username'} || $vars{'virclass'} || $vars{'anonymous'})) {

my $DIR = &varstoredir("",$vars{'username'},$vars{'virclass'},$vars{'anonymous'});

if ($DIR =~ /[A-Za-z0-9]/) {

if ($vars{'varstoreaction'} =~ /^load_(.*?)_(.*?)_(.*?)$/) {

$DIR .= $1;
my $FILE = "$2\_$3";

if (ONO::IO->exists("$DIR/$FILE.txt")) {

foreach my $line (ONO::IO->list("$DIR/$FILE.txt")) {
my @lp = split(/\^\:\^/,$line);
if ($lp[0] eq "VAR") {
$vars{$lp[1]} = $lp[2];
}
}

}
}

if ($vars{'varstoreaction'} eq "delete") {

ONO::IO->rmdir($DIR);

}
}
}

return (\%vars,%vars);

}

sub varstore {

#: Store exercise for later restart logic.

my (
$self,
$username,
$virclass,
$anonymous,
$vars_ref,
) = @_;

if ($username || $virclass) {

my %vars = %$vars_ref;

if ($vars{'output_web'} && $vars{'output_web_timer_start'}) {

my $DIR = &varstoredir("",$username,$virclass,$anonymous,$vars{'output_web_timer_start'});

if ($DIR) {

if ($vars{'output_web_finish'} || $vars{'output_progress_done'}) {

ONO::IO->rm("$DIR/$vars{'app_sid'}.txt");
ONO::IO->rmdir($DIR);

} else {

my $DATA;
foreach my $key (sort keys %vars) {
if ($vars{$key}) {
$DATA .= qq~VAR\^\:\^$key\^\:\^$vars{$key}\^\:\^\n~;
}
}

ONO::IO->mkpath($DIR);
ONO::IO->chmod($DIR,777);
ONO::IO->store("$DIR/$vars{'app_sid'}.txt",$DATA);
ONO::IO->chmod("$DIR/$vars{'app_sid'}.txt",777);
}
}
}
}
}

sub varstoreapp {

#: Store exercise for later restart logic.

$ENV{'REQUEST_URI'} =~ m~/cgi-bin/local/perl/(.*?)/apps/(.*?)\.pl~;

return $2;

}

sub varstoredir {

#: Store exercise for later restart logic.

my (
$self,
$username,
$virclass,
$anonymous,
$timestamp,
) = @_;

my $app = &varstoreapp();

if ($app) {

my $DIR = "users/".ONO::IO->deepdir($username)."/$username";
if (!$username) {
if ($virclass =~ /^(.*?):(.*?)$/) {
$DIR = "virclass/".ONO::IO->deepnum($1)."/$1/$2";
} else {
$DIR = "anonymous/$anonymous";
}
}

return "var/tmp/apps/exercises/$DIR/$app/$timestamp";

} else {

return "";

}

}

###################################################################
# var dump (dev mode only)
###################################################################

sub vardump {

#: Dump vars on developer station (debugging mode).

if (ONO::IO->devstation) {

my $vars_ref = $_[1];
my %vars = %$vars_ref;

my $VAR .= qq~<div class="block256"></div><div class="block256"></div>~;
my $DATA;

my $app;
if ($ENV{'SCRIPT_NAME'} =~ m~/cgi-bin/local/perl/school/apps/(.*?)\.pl~) {
$app = $1;
}

my $COOKIE = ONO::Lib::Web::Cookie->get("ono_app_${app}_settings");
foreach my $cdat (ONO::IO->list("var/tmp/cookies/apps/$COOKIE.txt")) {
if ($cdat =~ m~^(.*?)=(.*?)$~) {
$COOKIE .= qq~<br><span class="col9">cookie-data:</span> $1 = $2~;
}
}
$VAR .= qq~<div class="pad10_2 bt">Cookie:<br>ID: $COOKIE</div>~;

foreach my $key (sort keys %vars) {
if ($vars{$key} || $vars{$key} eq "0") {
$VAR .= qq~<div class="pad10_2 bt">$key -> $vars{$key}</div>~;
$DATA .= qq~$key -> $vars{$key}\n~;
}
}

ONO::IO->store("_apps_vardump.txt",$DATA);

return qq~$_[2]$VAR~;

} else {

return "";

}

}

###################################################################
# var flush
###################################################################

sub flush_cache {

#: Not used yet (deprecated?)

# my $vars_ref = $_[1];
# my %vars = %$vars_ref;
#
# foreach my $key (keys %vars) {
# if ($key =~ /^output_web_cache_/) {
# $vars{$key} = "";
# }
# }
#
# return \%vars;

}

###################################################################
# graphics elements
###################################################################

sub pdf_draw_house {

#: Deprecated here, moved to ONO_FW_Apps_Core_Graphics.

my (
$self,
$canvas,
$x,
$y,
$cols,
$res,
$op,
$corr,
) = @_;

return ONO::FW::Apps::Core::Graphics->pdf_draw_house(
$canvas,
$x,
$y,
$cols,
$res,
$op,
$corr,
);

}

sub pdf_draw_wall {

#: Deprecated here, moved to ONO_FW_Apps_Core_Graphics.

my (
$self,
$canvas,
$x,
$y,
$rows,
$nums_ref,
$op,
$numsys,
$mode,
$vars_ref,
$num_comma,
) = @_;

return ONO::FW::Apps::Core::Graphics->pdf_draw_wall(
$canvas,
$x,
$y,
$rows,
$nums_ref,
$op,
$numsys,
$mode,
$vars_ref,
$num_comma,
);

}

###################################################################
# LANG
###################################################################

sub lang_tenses {

#: Deprecated here, moved to ONO_FW_Apps_Core_Lang.

my ($ref1,$ref2,$ref3,$ref4,$ref5) = ONO::FW::Apps::Core::Lang->lang_tenses($_[1]);

return ($ref1,$ref2,$ref3,$ref4,$ref5);

}

sub lang_verbs_default {

#: Deprecated here, moved to ONO_FW_Apps_Core_Lang.

my $verbs = ONO::FW::Apps::Core::Lang->lang_verbs_default($_[1]);

return $verbs;

}

sub lang_verbs_add {

#: Deprecated here, moved to ONO_FW_Apps_Core_Lang.

my (
$self,
$db,
$community,
$option,
$lang,
$BLK_ref,
$vars_ref,
) = @_;

my $ADD = ONO::FW::Apps::Core::Lang->lang_verbs_add($db,$community,$option,$lang,$BLK_ref,$vars_ref);

return $ADD;

}

sub lang_verbs_persons {

#: Deprecated here, moved to ONO_FW_Apps_Core_Lang.

my @persons = ONO::FW::Apps::Core::Lang->lang_verbs_persons($_[1]);

return @persons;

}

sub lang_verbs_persons_list {

#: Deprecated here, moved to ONO_FW_Apps_Core_Lang.

my @persons = &lang_verbs_persons("",$_[1]);

return "$persons[0];$persons[1];$persons[2];$persons[3];$persons[4];$persons[5];";

}

###################################################################
# PRINT OPTS
###################################################################

sub print_design {

#: Select preferred print design (PDF).

my (
$self,
$id,
$lang,
$BLK_ref,
$switches,
) = @_;

my %BLK = %$BLK_ref;

my @txt = ONO::FW::Apps::Core::LangKit->print_design($lang);

my $SWITCH = ONO::Lib::UI::Check->switch("${id}_corrections",0,"mr");

my $WEB .= qq~<tr>
<td class="tar">$BLK{'design'}:</td>
<td>
<div class="select"><select name="$id">
<option value="default">$BLK{'default'}</option>
<option value="">----</option>
<option value="">$BLK{'none'}</option>
</select></div>
</td>
</tr>
~;

if ($switches =~ /c/) {

$WEB .= qq~<tr>
<td></td>
<td class="p0">
<table class="default_table">
<tr>
<td>$SWITCH</td>
<td>$txt[0]</td>
</tr>
</table>
</td>
</tr>
~;

}

return $WEB;

}

###################################################################
# VARIATION AND CUSTOM CODE
###################################################################

sub variation {

#: Detect platform variation.

my $VAR = "education.lu";

if ($ENV{'SERVER_NAME'} =~ /oli\.lu/i) {

$VAR = "oli";

}

if ($ENV{'SERVER_NAME'} =~ /morzino\.com/i) {

$VAR = "morzino";

}

if ($ENV{'SERVER_NAME'} =~ /(jamplifier)\.(com|org|net)/i || ONO::IO->community() eq "music") {

$VAR = "music";

}

if ($ENV{'SERVER_NAME'} =~ /(education|schoul)\.lu$/i || -e "/var/www/oli/cgi-bin/") {

$VAR = "education.lu";

}

if (ONO::IO->devstation) {

# $VAR = "oli";
# $VAR = "morzino";
# $VAR = "education.lu";
$VAR = "music";

}

return $VAR;

}

sub site {

#: Return site domain.

my $site = "oli.education.lu";

if (&variation =~ /morz/) {

$site = "morzino.com"

}

return $site;

}

sub sitename {

#: Return site name.

my $name = "Morzino";

if (&variation =~ /(oli|education)/ || ONO::IO->devstation) {

$name = "Oli"

}

return $name;

}

sub domain {

#: Return site domain.

my $domain = "oli.education.lu";

if (&variation =~ /morz/) {

$domain = "morzino.com"

}

return $domain;

}

###################################################################
# THAT'S IT :-D
###################################################################

1;

__END__