ONO::FW::Edu::Apps::Modules::Fractions

package ONO::FW::Edu::Apps::Modules::Fractions;
################################################################################
# COPYRIGHT / LICENSE #
################################################################################
#
# This file is part of the ONO Software Project.
#
# Copyright (C) 2022-2026 Jos Kirps and The Joopita Project [ASBL]
# Copyright (C) 2011-2022 Jos Kirps and Joopita Research ASBL
# Copyright (C) 2006-2011 Jos Kirps and The Joopita Project
# Copyright (C) 2001-2006 Jos Kirps and The WobbleWolf Project
#
# This file, as well as many 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 ... #
################################################################################

#: This module is a front end application module wrapper that has been
#: created for the Morzino Project (morzino.com) and that has been released
#: as Open Source software.
#:
#: Note that this is NOT a self-contained application, it is only a wrapper
#: that makes heavy use of the ONO Perl Framework application engine.

use strict;

use ONO::FW::Edu::Apps::ToolBox;
use ONO::FW::Edu::Apps::Modules::WorksheetMaker::Input;

use ONO::Lib::PDF::Draw;
use ONO::Lib::PDF::ToolBox;
use ONO::Lib::PDF::Elements;
use ONO::Lib::Math;
use ONO::Lib::Math::HTML;

use ONO::FW::Apps::Core;
use ONO::FW::Apps::Core::Graphics;
use ONO::FW::Apps::Core::Math;
use ONO::FW::Apps::Core::Check;

use ONO::Lib::Parser;

use ONO::FW::Apps::PDF;
use ONO::FW::Apps::ToolBox;

use ONO::IO;
use ONO::Lib::UI::Check;
use ONO::Lib::UI::Select;

sub learn {

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

################################################################
# INIT - BEGIN
################################################################

my (
$db,
$community,
$action_url,
$form,
$format,
$canvas,
$pdfkey,
$sec,$min,$hour,
$mday,$mon,$year,
$wday,$yday,$timestamp,
$lang,
$BLK_ref,
$vars_ref,
) = ONO::FW::Apps::Core->init($vars_ref);

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

my $app = "fractions";

my @txt = (
"calculate",
"reduce",
"to number",
"compare",
"charts (pies, bars, )",

"easy (often common denominator)",
"medium difficulty",
"hard (reduction often required)",

"max. 3 fractions",
"mix randomly",
);

if ($vars{'app_lang'} eq "de") {
@txt = (
"rechnen",
"kürzen",
"in Zahl umwandeln",
"vergleichen",
"Diagramme (Torten, Kästen, )",

"einfach (oft gemeinsamer Nenner)",
"mittel schwierig",
"schwierig (Kürzen oft erforderlich)",

"max. 3 Brüche",
"zufällig mischen",
);
}

if ($vars{'app_lang'} eq "lu") {
@txt = (
"rechnen",
"kierzen",
"an Zuel emwandelen",
"vergläichen",
"Diagrammer (Taarten, Këschten, ...)",

"einfach (oft gemeinsame Nenner)",
"mëttel schwéier",
"schwiereg (Kierzen oft néideg)",

"max. 3 Bréch",
"zufälleg meschen",
);
}

if ($vars{'app_lang'} eq "fr") {
@txt = (
"calculer",
"réduire",
"en nombres",
"comparer",
"diagrammes (tartes, boîtes, ...)",

"facile (souvent dénominateur commun)",
"difficulté normale",
"difficile (réductions souvent requises)",

"max. 3 fractions",
"mélanger par hasard",
);
}

ONO::FW::Apps::Core->now("",$app,$vars{'app_lang'});

my $WEB;

$WEB .= ONO::FW::Apps::Core->output_paper_save($pdfkey,$BLK_ref,\%vars,$HTTP,$BASE,"$year$mon$mday");

if (ONO::FW::Apps::Core->running(\%vars,$db)) {

$WEB .= ONO::FW::Apps::Core->blockbackbutton($BASE,$vars_ref);

#############################################################
# WORKSHEET MAKER
#############################################################

if ($vars{'output_worksheet_maker'}) {

$vars_ref = ONO::FW::Edu::Apps::Modules::WorksheetMaker::Input->vars(\%vars);
%vars = %$vars_ref;

}

#############################################################
# ONLINE TRAINING
#############################################################

if ($vars{'output_web'} || $vars{'output_paper'}) {

my $question_number = ONO::FW::Apps::Core->question_number($vars{'output_web_question_number'});

my ($focus_on,$page,$pages,%cache,$whilecounter,$stats_switches,$PDF_OPTS);

my ($stat_correct,$stat_wrong,$stat_todo,$stat_todo_total);

my $op_symbol_opts;

my $questions_per_page = 1;

if ($vars{'output_paper'}) {

$PDF_OPTS = ONO::FW::Apps::Core->headers_options($BLK_ref,$vars_ref);

ONO::FW::Apps::PDF->new("$BASE/pdf/pdf-$pdfkey.pdf","",$format);

$vars{'app_input_multiple_questions_per_page'}++;
$questions_per_page = 24;
$op_symbol_opts = "p";

if ($vars{'output_worksheet_maker'}) {
$questions_per_page = 6;
}

}

foreach my $copy (ONO::FW::Apps::Core->unique_copies($vars{'app_input_print_options_unique_copies'})) {

my ($pdf_x,$pdf_y) = (4.5,12);

my @corr_cache;

if ($vars{'output_paper'}) {

if ($copy > 1) {
ONO::FW::Apps::PDF->page("",$format);
}
ONO::FW::Apps::Core->headers(\%vars,$format);
ONO::FW::Apps::PDF->title($vars{'app_input_print_options_title'},$PDF_OPTS,$vars{'app_input_print_options_code'},$format);
ONO::FW::Apps::Core::Graphics->pdf_draw_item_numbers($canvas,-2,0,1,4,"HV",$vars_ref);

# ONO::Lib::PDF::ToolBox->canvas_test($canvas);

}

if ($vars{'output_web_next_question'}) {

$question_number++;
$vars{'output_web_question_number'}++;

foreach my $key (keys %vars) {
if ($key =~ /^output_web_(answer|cache)/) {
$vars{$key} = "";
}
}

}

if ($vars{'output_web'}) {

$WEB .= qq~<$form>~;

$op_symbol_opts = "c";

$WEB .= ONO::FW::Apps::Core->question_progress($vars{'app_input_number_of_questions'},$question_number);

}

if (ONO::FW::Apps::Core->question_progress_done($vars{'app_input_number_of_questions'},$question_number) || $vars{'output_web_finish'}) {

$vars{'output_progress_done'}++;

$WEB .= ONO::FW::Apps::Core->question_progress_done_msg($app,$db,$community,$form,$action_url,$vars{'app_input_number_of_questions'},$vars{'output_web_mistakes'},$lang,$BLK_ref,\%vars);

} else {

my @extypes;
foreach my $opt ('calc','redu','numb','comp','visu') {
if ($vars{"app_input_extype_$opt"}) {
@extypes = (@extypes,$opt);
}
}
my $extype_num = @extypes;
if (!$extype_num) {
$vars{"app_input_extype_calc"}++;
@extypes = ('calc');
$extype_num++;
}

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

if ($vars{'output_web'}) {

$stat_todo++;

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

$vars{"output_web_answer_${i}_$j"} =~ s~\,~\.~g;
$vars{"output_web_answer_${i}_$j"} = uc $vars{"output_web_answer_${i}_$j"};
$vars{"output_web_answer_${i}_$j"} =~ s~[^0-9\-\.]~~gi;

}

}

my ($DEBUG,$qtype,$qsize,$items,$illegal,$hide_ref,$nums_ref,$nums_simple_ref,$ops_ref,$visu_ref,@hide,@nums,@nums_simple,@ops,%visu,$whilecounter,$div_by_zero);

my $exclude = 1;
my $transmitted = 0;

if ($vars{'output_web_cache_qtype'} && $vars{'output_web_cache_items'}) {

$transmitted = 1;

$qtype = $vars{'output_web_cache_qtype'};
$items = $vars{'output_web_cache_items'};

for (my $t = 0; $t < 8; $t++) {
$nums[$t] = $vars{"output_web_cache_num_$t"};
$ops[$t] = $vars{"output_web_cache_ops_$t"};
$hide[$t] = $vars{"output_web_cache_hide_$t"};
}

foreach my $key (keys %vars) {
if ($key =~ /^output_web_cache_visu_(.*?)$/) {
$visu{$1} = $vars{$key};
}
}

}

while ($whilecounter < 256 && $exclude && !$transmitted) {

$exclude = 0;
$div_by_zero = 0;

$whilecounter++;

(
$DEBUG,
$qtype,
$qsize,
$items,
$illegal,
$hide_ref,
$nums_ref,
$nums_simple_ref,
$ops_ref,
$visu_ref,
) = &number_generator(
"",
$i,
\@extypes,
$extype_num,
\%vars,
);

if (ONO::IO->devstation) {
$WEB .= $DEBUG;
}

@hide = @$hide_ref;
@nums = @$nums_ref;
@nums_simple = @$nums_simple_ref;
@ops = @$ops_ref;
%visu = %$visu_ref;

$vars{"qsize_$i"} = $qsize;

# exclude if numbers are too big

if (abs($nums[0]) > $vars{'app_input_range_to'} || abs($nums[2]) > $vars{'app_input_range_to'} || abs($nums[4]) > $vars{'app_input_range_to'} || abs($nums[6]) > $vars{'app_input_range_to'}) {
$exclude++;
}

# exclude if two first numbers are integers (step 1)

my ($num1_is_int,$num2_is_int);

if ($nums[0] == 0 || $nums[1] == 1 || $nums[0] == $nums[1]) {
$num1_is_int++;
}
if ($nums[2] == 0 || $nums[3] == 1 || $nums[2] == $nums[3]) {
$num2_is_int++;
}

if ($num1_is_int && $num2_is_int) {
$exclude++;
}

if (!$vars{'app_input_negative'} && ($nums[0] < 0 || $nums[1] < 0 || $nums[2] < 0 || $nums[3] < 0 || $nums[4] < 0 || $nums[5] < 0 || $nums[6] < 0 || $nums[7] < 0)) {
$exclude++;
}

# exclude if division by zero

if ($illegal) {
$exclude++;
}
if ($nums[1] == 0 || $nums[3] == 0 || $nums[5] == 0 || $nums[7] == 0) {
$exclude++;
$div_by_zero++;
}

if ($ops[1] eq "div" && (($nums[2] ne "" && $nums[2] == 0) || ($nums[4] ne "" && $nums[4] == 0) || ($nums[6] ne "" && $nums[6] == 0))) {
$exclude++;
$div_by_zero++;
}

}

# cache the qtype and items for the number generator, to enable mixing visus and 4-items calcs for example...

$vars{"cache_qtype_$i"} = $qtype;
$vars{"cache_items_$i"} = $items;

# last check to kill divs by zero...

if ($div_by_zero) {
$items = 3;
@nums = ('1','1','1','1','1','1');
@ops = ("","div","=");
}

# output paper

if ($vars{'output_paper'}) {

# transfer visu to cache, for correction sheet

foreach my $key (keys %visu) {
$vars{"cache_visu_${i}_$key"} = $visu{$key};
}

# paper layout

if ($vars{'app_input_range_to'} > 100 || $items > 3) {
$qsize = "large";
$vars{"qsize_$i"} = "large";
}

if ($i > 11) {
my $j = $i-12;
my $k = $i-24;
if ($vars{"qsize_$j"} eq "large") {
$qsize = "large";
}
if ($vars{"qsize_$k"} eq "large") {
$qsize = "none";
}
}

if ($qsize eq "small" || $qsize eq "large") {

my @pos = (3,10.25,17.5, 25 ,32.5,39.75,47);
my $add_x;

if ($items == 2) {
@pos = (3,17.25,31.5);
$add_x = 9;
}

if ($qtype eq "comp" || $qtype eq "redu") {
$add_x = 0;
}

if ($qtype eq "numb") {
@pos = (3,10,20);
$add_x = 0;
}

if ($qtype eq "visu") {
@pos = (0,25,32.5,39,44);
$items = 2;
$add_x = 0;
$ops[1] = "=";
$hide[2]++;
}

my $mul_x = 1.05;

if ($qsize eq "large") {
$mul_x = 1.4;
}

$corr_cache[$i] = "$qtype\^$pdf_x\^$pdf_y\^$add_x\^$mul_x\^$items\^";
$corr_cache[$i] .= "$hide[1]\^$hide[2]\^$hide[3]\^$hide[4]\^";
$corr_cache[$i] .= "$pos[0]\^$pos[1]\^$pos[2]\^$pos[3]\^$pos[4]\^$pos[5]\^";
$corr_cache[$i] .= "$nums_simple[0]\^$nums_simple[1]\^$nums_simple[2]\^$nums_simple[3]\^$nums_simple[4]\^$nums_simple[5]\^$nums_simple[6]\^$nums_simple[7]\^";
$corr_cache[$i] .= "$ops[1]\^$ops[2]\^$ops[3]\^";

&pdf_gen_line(
"",
"",
$qtype,
$canvas,
$pdf_x,
$pdf_y,
$add_x,
$mul_x,
$items,
\@hide,
\@pos,
\@nums,
\@ops,
\%visu,
$vars{'app_input_integers'},
);

}

$pdf_y = $pdf_y + 20;

if ($i%2 != 0) {
$pdf_y = $pdf_y + 7.5;
}

if ($pdf_y > 190 || (($vars{'output_worksheet_maker'}) && $pdf_y > 40)) {

my $next_col_offset = 59;
if ($qsize eq "large") {
$next_col_offset = 65;
}
$pdf_x = $pdf_x + $next_col_offset;
$pdf_y = 12;

}

}

if ($vars{'output_web'}) {

my (@PARTS,@OPS,@CHK,$transmit_disabled,$answer_found,$answer_is_correct,$answer_incomplete);

my $CHK_SWITCHES = "BCS";

for (my $a0 = 0; $a0 < 4; $a0++) {
for (my $a1 = 0; $a1 < 2; $a1++) {
if ($vars{"output_web_answer_${a0}_${a1}"} ne "") {
$answer_found++;
}
}
}

if ($answer_found) {

my $relval;
if ($vars{'output_web_answer_0_1'}) {
$relval = $vars{'output_web_answer_0_0'}/$vars{'output_web_answer_0_1'};
}

if ($qtype eq "visu" && (($vars{'output_web_answer_0_0'} == $nums[0] && $vars{'output_web_answer_0_1'} == $nums[1]) || $relval == $nums[0]/$nums[1])) {
$answer_is_correct++;
}

if ($qtype eq "redu" && $vars{'output_web_answer_2_0'} == $nums[2] && $vars{'output_web_answer_2_1'} == $nums[3]) {
$answer_is_correct++;
}

if ($qtype eq "numb" && (!$relval || $relval == $nums[0]/$nums[1]) && $vars{'output_web_answer_0_2'} == $nums[0]/$nums[1]) {
$answer_is_correct++;
}

if ($qtype eq "calc") {
my ($errs,$errs_hard);
for (my $a = 0; $a < $items; $a++) {
my $aa0 = $a*2;
my $aa1 = $a*2+1;
if ($nums[$aa1]) {
my $err = 1;
my $err2;
if ($vars{"output_web_answer_${aa0}_1"}) {
if ($vars{"output_web_answer_${aa0}_0"}/$vars{"output_web_answer_${aa0}_1"} == $nums[$aa0]/$nums[$aa1]) {
$err = 0;
} else {
$errs_hard++;
}
}
if ($nums[$aa0] && $nums[$aa1] && (!$vars{"output_web_answer_${aa0}_0"} || !$vars{"output_web_answer_${aa0}_1"})) {
$answer_incomplete++;
}
$errs = $errs + $err;
}
}
if ($errs_hard) {
$answer_incomplete=0;
}
if (!$errs) {
$answer_is_correct++;
}
}

if ($answer_is_correct) {
$CHK_SWITCHES .= "G";
$WEB .= qq~<input type="hidden" name="output_web_next_question" value="1">
<script>onojs_submit_delayed(2);</script>
~;
} else {

if ($qtype eq "visu" || $qtype eq "redu") {

$CHK_SWITCHES .= "R";
$vars{'output_web_mistakes'}++;

}

if ($qtype eq "calc" && !$answer_incomplete) {

$CHK_SWITCHES .= "R";
$vars{'output_web_mistakes'}++;

}

if ($answer_incomplete) {

$CHK_SWITCHES .= "Y";

}

if ($qtype eq "numb") {

if ($relval && $relval != $nums[0]/$nums[1]) {
$CHK_SWITCHES .= "R";
$vars{'output_web_mistakes'}++;
}
if ($vars{'output_web_answer_0_2'} ne "" && $vars{'output_web_answer_0_2'} != $nums[0]/$nums[1]) {
$CHK_SWITCHES .= "R";
$vars{'output_web_mistakes'}++;
}

}

}

}

$WEB .= ONO::FW::Apps::Core->input_vars(\%vars);

if ($answer_is_correct) {
$CHK_SWITCHES .= "L";
} else {
$CHK_SWITCHES .= "b";
}

for (my $p = 0; $p < 4; $p++) {

if ($p < $items) {

my $pp0 = $p*2;
my $pp1 = $p*2+1;

if ($nums[$pp0] ne "" && $nums[$pp1] ne "") {
$PARTS[$p] = ONO::Lib::Math::HTML->display_number("$nums[$pp0]/$nums[$pp1]","fM");
$CHK[$p] = ONO::Lib::Math::HTML->display_number("$nums[$pp0]/$nums[$pp1]","fMiI","output_web_answer_$pp0",qq~$vars{"output_web_answer_${pp0}_0"}/$vars{"output_web_answer_${pp0}_1"}~);
if ($answer_is_correct || $qtype eq "comp") {
$CHK[$p] = $PARTS[$p];
}
if ($hide[$p+1] || $qtype eq "visu") {
$PARTS[$p] = qq~<div class="bold lightred ml10 mr10" style="font-size:64px">?</div>~;
$CHK[$p] = ONO::Lib::Math::HTML->display_number("$nums[$pp0]/$nums[$pp1]","fMiD","output_web_answer_$pp0",qq~$vars{"output_web_answer_${pp0}_0"}/$vars{"output_web_answer_${pp0}_1"}~);
}
if ($qtype eq "redu") {
$CHK[0] = ONO::Lib::Math::HTML->display_number("$nums[0]/$nums[1]","fM");
}
if ($answer_is_correct && $qtype eq "visu") {
$CHK[$p] = ONO::Lib::Math::HTML->display_number("$nums[$pp0]/$nums[$pp1]","fM");
}
}

if ($ops[$p]) {
$OPS[$p] = ONO::Lib::Math::HTML->op_to_symbol($ops[$p],"C");
}
}
}

my @OPS2 = @OPS;

if ($qtype eq "visu") {

$visu{'html'}++;
# $visu{'debug'}++;

$PARTS[0] = ONO::Lib::PDF::Elements->chart($canvas,$visu{'type'},0,0,280,140,1,\%visu);
$PARTS[1] = "";
$CHK[1] = "";


}

if ($qtype eq "comp") {

for (my $q = 1; $q < 3; $q++) {
if ($ops[$q] =~ /^comp-(.*?)$/) {

my $correct = $1;

my $CORR = 0;
if ($correct eq "eq") {
$CORR = 1;
}
if ($correct eq "gt") {
$CORR = 2;
}

my $SOL = ONO::Lib::Math::HTML->op_to_symbol($correct);
my $SYM;

my @BUTS = ONO::FW::Apps::Core::Math->compare_buttons($i,$CORR,$SOL,$SYM,$stat_wrong,$questions_per_page,\%vars);

$WEB .= ONO::FW::Apps::Core::Math->compare_script();
$WEB .= qq~<input type="hidden" name="output_web_next_question" value="1">~;

# $OPS[$q] = qq~<div class="block40 bg_yellow bo lightred bold radius20">?</div>~;
$OPS2[$q] = qq~<table class="default_table">
<tr>
<td class="p0">$BUTS[0]</td>
<td class="p0">$BUTS[1]</td>
<td class="p0">$BUTS[2]</td>
</tr>
</table>
~;

}
}

}

if ($qtype eq "numb") {

my $res = $nums[0]/$nums[1];

my $PLA;
if (ONO::IO->devstation) {
$PLA = qq~ placeholder="$res"~;
}

$CHK[1] = qq~<div class="pad10_2"><input type="text" name="output_web_answer_0_2" value="$vars{'output_web_answer_0_2'}" class="w100"$PLA></div>~;

}

$WEB .= ONO::FW::Apps::Core::Math->compare_input($stat_correct,$vars{'output_web_mistakes'},$stat_wrong,$stat_todo);

if (!$transmit_disabled) {

$WEB .= qq~<input type="hidden" name="output_web_cache_qtype" value="$qtype">
<input type="hidden" name="output_web_cache_items" value="$items">
~;

for (my $t = 0; $t < 8; $t++) {
$WEB .= qq~<input type="hidden" name="output_web_cache_num_$t" value="$nums[$t]">
<input type="hidden" name="output_web_cache_ops_$t" value="$ops[$t]">
<input type="hidden" name="output_web_cache_hide_$t" value="$hide[$t]">
~;
}

foreach my $key (keys %visu) {
$WEB .= qq~<input type="hidden" name="output_web_cache_visu_$key" value="$visu{$key}">~;
}

}

$WEB .= ONO::FW::Apps::Core->stats("",$BLK_ref,"ctmW");

$WEB .= qq~<div class="inline auto">~;

if ($qtype eq "comp") {

$WEB .= qq~<div class="block32"></div>~;

} else {

$CHK_SWITCHES .= "T";

$WEB .= qq~ <div class="box_black flat_bottom mt20">
<div class="box_paper xlarge">
<table class="wide_table">
<tr>
<td class="p0 center">$PARTS[0]</td>
<td class="p0 center">$OPS[1]</td>
<td class="p0 center">$PARTS[1]</td>
<td class="p0 center">$OPS[2]</td>
<td class="p0 center">$PARTS[2]</td>
<td class="p0 center">$OPS[3]</td>
<td class="p0 center">$PARTS[3]</td>
</tr>
</table>
</div>
</div>
~;

}

$WEB .= ONO::FW::Apps::Core::Check->check_custom(
qq~<td class="p0">$CHK[0]</td>
<td class="p0">$OPS2[1]</td>
<td class="p0">$CHK[1]</td>
<td class="p0">$OPS2[2]</td>
<td class="p0">$CHK[2]</td>
<td class="p0">$OPS2[3]</td>
<td class="p0">$CHK[3]</td>
<td class="p0"><img id="loading_img" class="hide" src="/ono/osr/images/spacer/trans.gif" alt=""></td>
~,
$CHK_SWITCHES,
"",
"",
$BLK{'do_correct'},
);

$WEB .= qq~ </div>
</form>
~;

}
}
}

if (ONO::FW::Apps::Core->print_corrections("$BASE/pdf/pdf-$pdfkey-corr.pdf","",$format,$vars_ref)) {

ONO::FW::Apps::Core->headers(\%vars,$format,"c");
ONO::FW::Apps::PDF->title($BLK{'Corrections'},$PDF_OPTS,$vars{'app_input_print_options_code'},$format);
ONO::FW::Apps::Core::Graphics->pdf_draw_item_numbers($canvas,-2,0,1,4,"HV",$vars_ref);

# ONO::Lib::PDF::ToolBox->canvas_test($canvas);

for (my $c = 0; $c < $questions_per_page; $c++) {

my (@hide,@pos,@nums,@ops,%visu);

my ($qtype,$pdf_x,$pdf_y,$add_x,$mul_x,$items,@rest) = split(/\^/,$corr_cache[$c]);

(
$hide[1],$hide[2],$hide[3],$hide[4],
$pos[0],$pos[1],$pos[2],$pos[3],$pos[4],$pos[5],
$nums[0],$nums[1],$nums[2],$nums[3],$nums[4],$nums[5],$nums[6],$nums[7],
$ops[1],$ops[2],$ops[3],
) = @rest;

foreach my $key (keys %vars) {
if ($key =~ /^cache_visu_${c}_(.*?)$/) {
my $key2 = $1;
$visu{$key2} = $vars{$key};
if ($key =~ /element_(.*?)_color/ && $vars{$key} ne "0:244:244:244") {
$visu{$key2} = "0:111:111:111";
}
}
}

&pdf_gen_line(
"",
"c",
$qtype,
$canvas,
$pdf_x,
$pdf_y,
$add_x,
$mul_x,
$items,
\@hide,
\@pos,
\@nums,
\@ops,
\%visu,
$vars{'app_input_integers'},
);

}
}

}

if ($vars{'output_web'}) {

# ($stat_correct,$stat_todo_total) = ONO::FW::Apps::Core->stats_multi_pages($vars{'app_input_number_of_questions'},$stat_correct,$stat_wrong,$page,$pages);

$stat_correct = $question_number-1;
$stat_todo_total = $vars{'app_input_number_of_questions'} - $stat_correct;

$WEB = ONO::FW::Apps::Core->stats_replace($WEB,$stat_correct,$stat_wrong,$stat_todo_total,$vars{'output_web_mistakes'},$page,$pages,$vars{'output_web_completed'});

}

if ($vars{'output_paper'}) {

ONO::FW::Apps::PDF->end;

$WEB .= ONO::FW::Apps::PDF->please_wait($pdfkey,\%BLK,\%vars,"",$HTTP,$BASE);

}

}

} else {

#############################################################
# EXERCISE SETUP
#############################################################

if (!$vars{'app_input_number_of_questions'}) {
$vars{'app_input_number_of_questions'} = 20;
}

$WEB .= ONO::FW::Apps::Core->infopics(
"screen:320:50:50::fractions_screenshot_1.jpg",
"sheet:168:180:135:15:fractions_sheet_1.jpg",
"sheet:168:40:155:-10:fractions_sheet_2.jpg",
);

if (!$vars{'app_input_range_to'}) {
$vars{'app_input_range_to'} = 50;
}

if (!$vars{'app_input_extype_redu'} && !$vars{'app_input_extype_calc'} && !$vars{'app_input_extype_numb'} && !$vars{'app_input_extype_comp'} && !$vars{'app_input_extype_visu'}) {
$vars{'app_input_integers'}++;
$vars{'app_input_extype_visu'}++;
$vars{'app_input_extype_redu'}++;
$vars{'app_input_extype_numb'}++;
$vars{'app_input_extype_comp'}++;
$vars{'app_input_extype_calc'}++;
$vars{'app_input_select_level'} = "hard";
}

if (!$vars{'app_input_range_opts'}) {
$vars{'app_input_range_opts'} = "auto";
}

if (!$vars{'app_input_extype_status'}) {
$vars{'app_input_extype_status'} = "std";
}

my (%setup,$hide);

my @tabs = ("std:green:a + b = ?","var:green:a + ? = c","mix:green:mix");

my $CUSTOM2 = ONO::Lib::UI::Select->buttons(
"app_input_extype",
$vars{'app_input_extype_status'},
\@tabs,
"",
"f",
$BLK_ref,
\%setup,
);

my $IFP = " , $BLK{'if_possible'} ";
$IFP =~ s~\ \;~ ~g;

my $CONF;

$CONF .= ONO::FW::Apps::ToolBox->conf_input("range", $BLK_ref,\%vars,"",1,100,9999,"Dhmu","auto=$txt[8];-;mix=$txt[9] ( 1 - 4 );-;1=1 ( A$IFP);2=2 ( A, B$IFP);3=3 ( A, B, C$IFP);4=4 ( A, B, C, D$IFP)");
$CONF .= ONO::FW::Apps::ToolBox->conf_input("intneg", $BLK_ref,\%vars,"");
$CONF .= ONO::FW::Apps::ToolBox->conf_input("spacer", $BLK_ref,\%vars,"","s");
$CONF .= ONO::FW::Apps::ToolBox->conf_input("ops", $BLK_ref,\%vars,"","asmd-AS");
$CONF .= ONO::FW::Apps::ToolBox->conf_input("spacer", $BLK_ref,\%vars,"","s");
$CONF .= ONO::FW::Apps::ToolBox->conf_input("select", $BLK_ref,\%vars,"","easy=$txt[5];mid=$txt[6];hard=$txt[7]","",$vars{'app_input_select_level'},"","level");
$CONF .= ONO::FW::Apps::ToolBox->conf_input("spacer", $BLK_ref,\%vars,"","s");
$CONF .= ONO::FW::Apps::ToolBox->conf_input_box_open("paper");

$CONF .= ONO::FW::Apps::ToolBox->conf_input("check", $BLK_ref,\%vars,"","","extype_visu",$vars{'app_input_extype_visu'},"$txt[4]");
$CONF .= ONO::FW::Apps::ToolBox->conf_input("check", $BLK_ref,\%vars,"","","extype_comp",$vars{'app_input_extype_comp'},"$txt[3] ( < = > )");
$CONF .= ONO::FW::Apps::ToolBox->conf_input("check", $BLK_ref,\%vars,"","","extype_redu",$vars{'app_input_extype_redu'},"$txt[1] ( 2/4 → 1/2 )");
$CONF .= ONO::FW::Apps::ToolBox->conf_input("check", $BLK_ref,\%vars,"","","extype_numb",$vars{'app_input_extype_numb'},"$txt[2] ( 1/2 → 0.5 )");
$CONF .= ONO::FW::Apps::ToolBox->conf_input("check", $BLK_ref,\%vars,"","","extype_calc",$vars{'app_input_extype_calc'},"$txt[0] ( + / – / • / : )");
$CONF .= ONO::FW::Apps::ToolBox->conf_input("custom", $BLK_ref,\%vars,"","",qq~<div class="inline ml30">$CUSTOM2</div>~);

$CONF .= ONO::FW::Apps::ToolBox->conf_input_box_close();

$WEB .= ONO::FW::Apps::Core->conf_box(
$db,
$community,
$app,
$form,
"",
$action_url,
$CONF,
$lang,
$BLK_ref,
\%vars,
"op-ncdi-CDI-lsu-N",
);
if (!$vars{'exercise'}) {
$WEB .= ONO::FW::Apps::Core->info_display(
ONO::FW::Apps::Core->info("info_online_print",$vars{'app_lang'}),
ONO::FW::Apps::Core->info("info_indiv_diff", $vars{'app_lang'}),
);
}

}

my ($status,$WEB) = ONO::Lib::Parser->parse($WEB,$vars_ref);

$WEB .= ONO::FW::Apps::Core->vardump($vars_ref);

$WEB = ONO::FW::Edu::Apps::ToolBox->apps_gate($WEB,$vars_ref);

return $WEB;

}

###################################################################
# SUBS
###################################################################

sub number_generator {

my (
$self,
$i,
$extypes_ref,
$extype_num,
$vars_ref,
) = @_;

my @extypes = @$extypes_ref;
my %vars = %$vars_ref;

# main logic for web and paper

my $items = 2;
my $qsize = "small";
my ($DEBUG,@ops,@hide,%visu,$illegal);

my $qtype = $extypes[int(rand($extype_num))];

if ($qtype eq "comp" || $qtype eq "calc") {
if ($vars{'app_input_range_opts'} eq "auto" || $vars{'app_input_range_opts'} == 1) {
$items = 2;
}
if ($vars{'app_input_range_opts'} =~ /^(2|3|4)$/) {
$items = $vars{'app_input_range_opts'};
}
if ($vars{'app_input_range_opts'} eq "mix") {
$items = 2+int(rand(3));
}
if ($qtype eq "comp" && $vars{'app_input_extype_calc'} && int(rand(100)) > 33) {
$items = 3;
}
}

# make sure mixing visus and others will work properly...

if ($items == 4) {

my $j = $i-12;
my $k = $i-24;

if ($vars{"cache_qtype_$j"} eq "visu" || $vars{"cache_qtype_$k"} eq "visu") {
$items = 3;
}

}

# if ($qtype eq "visu") {
#
# my $j = $i-12;
## my $k = $i-24;
#
# if ($vars{"cache_qtype_$j"} ne "visu" && $vars{"cache_items_$j"} == 4) {
# $qtype = $vars{"cache_qtype_$j"};
# # $items = 4;
# # $qtype = "calc";
# }
#
# }

if ($qtype eq "calc") {
if ($items < 3) {
$items = 3;
}
for (my $o = 1; $o < $items+1; $o++) {
$ops[$o] = ONO::FW::Apps::Core->random_operation(ONO::FW::Apps::Core->get_operations($vars_ref));
}

# if ($vars{'app_input_extype_status'} eq "std") {
$ops[$items-1] = "=";
# $hide[$items]++;
# }
# if ($vars{'app_input_extype_status'} eq "var" || $vars{'app_input_extype_status'} eq "mix") {
# $ops[1+int(rand($items-1))] = "=";
# $hide[1+int(rand($items-1))]++;
# }
}

my @nums = (1,1,1,1,1,1,1,1);

my $common = 1+(int(rand($vars{'app_input_range_to'}))-1);

my $max = sqrt($vars{'app_input_range_to'})*1.5;
if ("$ops[1]$ops[2]$ops[3]" =~ /(mul|div)/) {
$max = $max/2;
}

($nums[0],$nums[2],$nums[4],$nums[6]) = (int(rand($max)),int(rand($max)),int(rand($max)),int(rand($max)));
($nums[1],$nums[3],$nums[5],$nums[7]) = ($common,$common,$common,$common);

# make zeroes less probable

foreach my $z (0,2,4,6) {
if ($nums[$z] == 0 && int(rand(100)) > 33) {
$nums[$z] = 1+int(rand($max));
}
}

# no easy mode, or mul/div -> don't use common denominator

if ($vars{'app_input_select_level'} ne "easy" || "$ops[1]$ops[2]$ops[3]" =~ /(mul|div)/) {

my (@alt,$cumul,$whilecounter);
while ($whilecounter < 256 && ($cumul < 2 || $cumul > $vars{'app_input_range_to'})) {
$whilecounter++;
@alt = (1+int(rand($max)),1+int(rand($max)),1+int(rand($max)));
$cumul = $alt[0]*$alt[1];
if ($items > 3) {
$cumul = $alt[0]*$alt[1]*$alt[2];
}
}
if ($cumul > 1 && $cumul < $vars{'app_input_range_to'}) {
($nums[1],$nums[3],$nums[5]) = @alt;
}

}

if ($vars{'app_input_negative'}) {

# randomly insert negative numbers

for (my $n = 0; $n < 8; $n++) {
if (int(rand(100)) > 66) {
$nums[$n] = -$nums[$n];
}
}

} else {

# avoid negative results

if ($qtype eq "calc") {

if ($items == 3 && $ops[1] eq "sub" && $nums[1] && $nums[3]) {

if ($nums[0]/$nums[1] < $nums[2]/$nums[3]) {
my @cache = ($nums[0],$nums[1]);
($nums[0],$nums[1]) = ($nums[2],$nums[3]);
($nums[2],$nums[3]) = @cache;
}

}

}

}

# calculate results

if ($qtype eq "calc") {

if ($items == 3) {

($nums[4],$nums[5]) = ();

if ($ops[1] eq "add") {

$nums[4] = ($nums[0]*$nums[3]+$nums[2]*$nums[1]);
$nums[5] = $nums[1]*$nums[3];

}

if ($ops[1] eq "sub") {

$nums[4] = ($nums[0]*$nums[3]-$nums[2]*$nums[1]);
$nums[5] = $nums[1]*$nums[3];

}

if ($ops[1] eq "mul") {

$nums[4] = $nums[0]*$nums[2];
$nums[5] = $nums[1]*$nums[3];

}

if ($ops[1] eq "div") {

$nums[4] = $nums[0]*$nums[3];
$nums[5] = $nums[1]*$nums[2];

}

if (($vars{'app_input_extype_status'} eq "var" || $vars{'app_input_extype_status'} eq "mix")) {

if (($ops[1] eq "add" || $ops[1] eq "sub") && $vars{'app_input_op_add'} && $vars{'app_input_op_sub'}) {

# this currently only works for add and sub...

my @nums = ($nums[4],$nums[5],$nums[0],$nums[1],$nums[2],$nums[3],1,1);
my $rev = "add";
if ($ops[1] eq "add") {
$rev = "sub";
}
@ops = ("","=",$rev);

}

}

my $question = 3;
if ($vars{'app_input_extype_status'} eq "var") {
$question = 1+int(rand(2));
}
if ($vars{'app_input_extype_status'} eq "mix") {
$question = 1+int(rand(3));
}
if ($nums[0] == 0 || $nums[2] == 0 || $nums[3] == 0) {
$question = 3;
}

$hide[$question]++;
($nums[$question+1],$nums[$question+2]) = ONO::Lib::Math->fraction_reducer($nums[$question+1],$nums[$question+2],1);

}

if (ONO::IO->devstation()) {

# @ops=('','div','div','=');

}

if ($items == 4) {

($nums[6],$nums[7]) = ();

my $top1 = $nums[0]*$nums[3]*$nums[5];
my $top2 = $nums[2]*$nums[1]*$nums[5];
my $top3 = $nums[4]*$nums[1]*$nums[3];

$nums[7] = $nums[1]*$nums[3]*$nums[5];

if ($ops[1] eq "add") {

if ($ops[2] eq "add") {
$nums[6] = $top1+$top2+$top3;
}

if ($ops[2] eq "sub") {
$nums[6] = $top1+$top2-$top3;
}

if ($ops[2] eq "mul") {
$nums[6] = $top1+$top2*$top3;
}

if ($ops[2] eq "div") {
if ($top3 == 0) {
$illegal++;
} else {

my $div1 = $nums[2]*$nums[5];
my $div2 = $nums[4]*$nums[3];

$nums[6] = ($nums[0]*$div2+$nums[1]*$div1);
$nums[7] = $nums[1]*$div2;

}
}

}

if ($ops[1] eq "sub") {

if ($ops[2] eq "add") {
$nums[6] = $top1-$top2+$top3;
}

if ($ops[2] eq "sub") {
$nums[6] = $top1-$top2-$top3;
}

if ($ops[2] eq "mul") {
$nums[6] = $top1-$top2*$top3;
}

if ($ops[2] eq "div") {
if ($top3 == 0) {
$illegal++;
} else {

my $div1 = $nums[2]*$nums[5];
my $div2 = $nums[4]*$nums[3];

$nums[6] = ($nums[0]*$div2-$nums[1]*$div1);
$nums[7] = $nums[1]*$div2;

}
}

}

if ($ops[1] eq "mul") {

if ($ops[2] eq "add") {
$nums[6] = $top1*$top2+$top3;
}

if ($ops[2] eq "sub") {
$nums[6] = $top1*$top2-$top3;
}

if ($ops[2] eq "mul") {
$nums[6] = $top1*$top2*$top3;
}

if ($ops[2] eq "div") {
if ($top3 == 0) {
$illegal++;
} else {

$nums[6] = $nums[0]*$nums[2]*$nums[5];
$nums[7] = $nums[1]*$nums[4]*$nums[3];

}
}

}

if ($ops[1] eq "div") {

if ($ops[2] eq "add") {
if ($top2 == 0) {
$illegal++;
} else {

my $div1 = $nums[0]*$nums[3];
my $div2 = $nums[2]*$nums[1];

$nums[6] = ($nums[4]*$div2+$nums[5]*$div1);
$nums[7] = $nums[5]*$div2;

}
}

if ($ops[2] eq "sub") {
if ($top2 == 0) {
$illegal++;
} else {

my $div1 = $nums[0]*$nums[3];
my $div2 = $nums[2]*$nums[1];

$nums[6] = ($nums[5]*$div1-$nums[4]*$div2);
$nums[7] = $nums[5]*$div2;

}
}

if ($ops[2] eq "mul") {
if ($top2 == 0 || $top3 == 0) {
$illegal++;
} else {

$nums[6] = $nums[0]*$nums[3]*$nums[4];
$nums[7] = $nums[1]*$nums[2]*$nums[5];

}
}

if ($ops[2] eq "div") {
if ($top2 == 0 || $top3 == 0) {
$illegal++;
} else {

$nums[6] = $nums[0]*$nums[3]*$nums[5];
$nums[7] = $nums[1]*$nums[2]*$nums[4];


}
}

}

my $question = 4;
if ($vars{'app_input_extype_status'} eq "var") {
$question = 1+int(rand(3));
}
if ($vars{'app_input_extype_status'} eq "mix") {
$question = 1+int(rand(4));
}
if ($nums[0] == 0 || $nums[2] == 0 || $nums[3] == 0 || $nums[4] == 0) {
$question = 4;
}

$hide[$question]++;
($nums[$question+2],$nums[$question+3]) = ONO::Lib::Math->fraction_reducer($nums[$question+2],$nums[$question+3],1);

}

}

# generate comp numbers

if ($qtype eq "comp") {

if ($items == 4) {
$items = 3;
}

if ($items == 2) {

$ops[1] = "comp";

if ($nums[1] && $nums[3]) {

my $num1 = $nums[0]/$nums[1];
my $num2 = $nums[2]/$nums[3];

$ops[1] = "comp-".ONO::Lib::Math->comp($num1,$num2);

}

}

if ($items == 3) {

my ($num1,$num2,$num3);

if ($nums[1] && $nums[3] && $nums[5]) {

$num1 = $nums[0]/$nums[1];
$num2 = $nums[2]/$nums[3];
$num3 = $nums[4]/$nums[5];

}

my $rand_max = 3;
if ($vars{'output_web'}) {
$rand_max = 2;
}

my $rand = int(rand($rand_max));

if ($rand == 0) {
$ops[1] = ONO::FW::Apps::Core->random_operation(ONO::FW::Apps::Core->get_operations($vars_ref));
if (!$num2) {
$ops[1] = "add";
}

my $res = ONO::Lib::Math->calc($num1,$num2,$ops[1]);

$ops[2] = "comp-".ONO::Lib::Math->comp($res,$num3);

}

if ($rand == 1) {
$ops[2] = ONO::FW::Apps::Core->random_operation(ONO::FW::Apps::Core->get_operations($vars_ref));
if (!$num3) {
$ops[2] = "add";
}

my $res = ONO::Lib::Math->calc($num2,$num3,$ops[2]);

$ops[1] = "comp-".ONO::Lib::Math->comp($num1,$res);
}

if ($rand == 2) {

$ops[1] = "comp-".ONO::Lib::Math->comp($num1,$num2);
$ops[2] = "comp-".ONO::Lib::Math->comp($num2,$num3);

}

}
}

# reductions

if ($qtype eq "redu") {

$items = 2;
$ops[1] = "=";
$hide[2]++;

if (int(rand(100)) > 20) {
my @rands = (2,3,4,5,6,7); #,8,9,10,11,12,13);
my $rands_num = @rands;

if ($nums[0] == 0) {
$nums[0] = $rands[int(rand($rands_num))];
}

my $whilecounter;
if ($whilecounter < 32 && $nums[0] < $vars{'app_input_range_to'}/1.5 && $nums[1] < $vars{'app_input_range_to'}/1.5) {
$whilecounter++;
my $rand = $rands[int(rand($rands_num))];
if ($nums[0]*$rand < $vars{'app_input_range_to'} && $nums[1]*$rand < $vars{'app_input_range_to'}) {
$nums[0] = $nums[0]*$rand;
$nums[1] = $nums[1]*$rand;
}
}
}

($nums[2],$nums[3]) = ONO::Lib::Math->fraction_reducer($nums[0],$nums[1],1);

}

# fraction to number

if ($qtype eq "numb") {

$items = 2;
$ops[1] = "=";
$hide[2]++;

my $res = $nums[0]/$nums[1];

my $whilecounter;
while ($whilecounter < 64 && length $res > 4) {
$whilecounter++;
$nums[0] = 1;
$nums[1] = 2;
$res = $nums[0]/$nums[1];
}

if (length ($nums[0]/$nums[1]) > 5) {
$nums[0] = 1;
$nums[1] = 2;
}

$nums[2] = $nums[0];
$nums[3] = $nums[1];

}

# cache initial numbers

my @nums_simple = @nums;

# hard mode: make numbers bigger, reduction required

if ($vars{'app_input_select_level'} eq "hard") {

my @opts = (0,2);
if ($items == 4) {
@opts = (0,2,4);
}
if ($qtype eq "redu" || $qtype eq "numb") {
@opts = (0);
}

foreach my $n (@opts) {
if ($nums[$n] != $nums[$n+1] || int(rand(100)) > 66) {
my $rand = 1+int(rand($max));
if ($nums[$n]*$rand < $vars{'app_input_range_to'} && $nums[$n+1]*$rand < $vars{'app_input_range_to'}) {
$nums[$n] = $nums[$n]*$rand;
$nums[$n+1] = $nums[$n+1]*$rand;
}
}
}

}

if ($qtype eq "visu") {

$qsize = "small";

my $max = $vars{'app_input_range_to'};
if ($max > 32) {
$max = 32;
}

$nums[1] = 1+int(rand($max));
$nums[0] = int(rand($nums[1]+1));

$nums[2] = $nums[0];
$nums[3] = $nums[1];

$nums_simple[0] = $nums[0];
$nums_simple[1] = $nums[1];

$nums_simple[2] = $nums[0];
$nums_simple[3] = $nums[1];

$visu{"elements"} = $nums[1];

my ($r,$g,$b) = (25+int(rand(175)),25+int(rand(175)),25+int(rand(175)));

for (my $p = 1; $p < $visu{"elements"}+1; $p++) {

if ($visu{"elements"} > 1) {
$visu{"element_${p}_degrees"} = 360/$visu{"elements"};
}

$visu{"element_${p}_percent"} = 100/$visu{"elements"};
if ($p < $nums[0]+1) {
$visu{"element_${p}_color"} = "0:$r:$g:$b";
} else {
$visu{"element_${p}_color"} = "0:244:244:244";
}

}

if (($nums[1] < 10 || ($nums[1]%2 == 0 && $nums[1] < 13)) && int(rand(100)) > 50) {

$visu{"type"} = "pie";

} else {

if ($nums[1] < 11 && int(rand(100)) > 50) {

$visu{'rows'} = 1;
$visu{'cols'} = $nums[1];
$visu{"type"} = "bar";

if ($nums[1] < 6 && int(rand(100)) > 50) {
$visu{'rows'} = $nums[1];
$visu{'cols'} = 1;
$visu{'ori'} = "v";
}

} else {

if ($nums[1]%4 == 0 && int(rand(100)) > 10) {

$visu{'rows'} = 4;
$visu{'cols'} = $nums[1]/4;
$visu{"type"} = "bar";

} else {

if ($nums[1] < 31 && $nums[1]%3 == 0 && int(rand(100)) > 20) {

$visu{'rows'} = 3;
$visu{'cols'} = $nums[1]/3;
$visu{"type"} = "bar";

} else {

if ($nums[1] < 21 && $nums[1]%2 == 0 && int(rand(100)) > 30) {

$visu{'rows'} = 2;
$visu{'cols'} = $nums[1]/2;
$visu{"type"} = "bar";

} else {

$visu{"type"} = "dots";

}

}

}

}

}

}

return ($DEBUG,$qtype,$qsize,$items,$illegal,\@hide,\@nums,\@nums_simple,\@ops,\%visu);

}

sub pdf_gen_line {

my (
$self,
$switches,
$qtype,
$canvas,
$pdf_x,
$pdf_y,
$add_x,
$mul_x,
$items,
$hide_ref,
$pos_ref,
$nums_ref,
$ops_ref,
$visu_ref,
$integers,
) = @_;

my @hide = @$hide_ref;
my @pos = @$pos_ref;
my @nums = @$nums_ref;
my @ops = @$ops_ref;
my %visu = %$visu_ref;

my @hide_dev;

if ($switches =~ /c/) {
@hide = ();
}

if ($qtype eq "visu") {

my %data = %visu;

my $visu_x = $mul_x*($pdf_x+$pos[0])+$add_x/2;
my $visu_w = 21;
if ($data{'type'} eq "pie") {
$visu_x = $visu_x + 4;
$visu_w = 14;
}

ONO::Lib::PDF::Elements->chart( $canvas,$data{'type'},0.5+$visu_x,$pdf_y-7,$visu_w,14,1,\%data);

}

if ($qtype ne "visu") {

&pdf_gen_line_item("", 1,$canvas,$pdf_x,$pdf_y,$add_x,$mul_x,$hide[1],$hide_dev[1],$pos[0],$nums[0],$nums[1],$qtype,$integers,$switches);

}

&pdf_gen_line_op("", 1,$canvas,$pdf_x,$pdf_y,$add_x,$mul_x,$pos[1],$ops[1],$qtype,$switches);

if ($items > 1) {

&pdf_gen_line_item("", 2,$canvas,$pdf_x,$pdf_y,$add_x,$mul_x,$hide[2],$hide_dev[2],$pos[2],$nums[2],$nums[3],$qtype,$integers,$switches);

if ($items > 2) {

&pdf_gen_line_op("", 3,$canvas,$pdf_x,$pdf_y,$add_x,$mul_x,$pos[3],$ops[2],$qtype,$switches);

&pdf_gen_line_item("", 4,$canvas,$pdf_x,$pdf_y,$add_x,$mul_x,$hide[3],$hide_dev[3],$pos[4],$nums[4],$nums[5],$qtype,$integers,$switches);

if ($items > 3) {

&pdf_gen_line_op("", 5,$canvas,$pdf_x,$pdf_y,$add_x,$mul_x,$pos[5],$ops[3],$qtype,$switches);

&pdf_gen_line_item("", 6,$canvas,$pdf_x,$pdf_y,$add_x,$mul_x,$hide[4],$hide_dev[4],$pos[6],$nums[6],$nums[7],$qtype,$integers,$switches);

}
}
}
}

sub pdf_gen_line_item {

my (
$self,
$id,
$canvas,
$pdf_x,
$pdf_y,
$add_x,
$mul_x,
$hide,
$hide_dev,
$pos,
$num1,
$num2,
$qtype,
$integers,
$switches,
) = @_;

if (!$hide) {

my $alt;
if ($qtype eq "numb" && $id == 2 && $switches =~ /c/) {
$alt = $num1/$num2;
$alt = substr($alt,0,10);
}

if ($alt eq "" && ($qtype !~ /(redu|numb)/ || $switches =~ /c/) && $integers && ($num1 == 0 || $num2 == 1 || $num1 == $num2)) {
if ($num1 == $num2) {
$num1 = 1;
}
ONO::Lib::PDF::Draw->text( $canvas,$mul_x*($pdf_x+$pos)+$add_x/2, $pdf_y+1, $num1,"c");
} else {
if ($alt ne "") {
ONO::Lib::PDF::Draw->text( $canvas,$mul_x*($pdf_x+$pos)+$add_x/2-6, $pdf_y+1, $alt,"");
} else {
ONO::Lib::PDF::Draw->line( $canvas,$mul_x*($pdf_x+$pos-3), $pdf_y, $mul_x*($pdf_x+$pos+3)+$add_x, $pdf_y);
ONO::Lib::PDF::Draw->text( $canvas,$mul_x*($pdf_x+$pos)+$add_x/2, $pdf_y-1.5, $num1,"c");
ONO::Lib::PDF::Draw->text( $canvas,$mul_x*($pdf_x+$pos)+$add_x/2, $pdf_y+4, $num2,"c");
}
}
if ($hide_dev) {
ONO::Lib::PDF::Draw->line( $canvas,$mul_x*($pdf_x+$pos-3), $pdf_y, $mul_x*($pdf_x+$pos)-1, $pdf_y,5);
}
} else {
if ($qtype eq "numb") {
ONO::Lib::PDF::Draw->rect( $canvas,$mul_x*($pdf_x+$pos-5)+$add_x/2, $pdf_y-5, $mul_x*($pdf_x+$pos+5)+$add_x+14, $pdf_y+5,1,"0:0:0:0","0:244:244:244",2);
} else {
ONO::Lib::PDF::Draw->rect( $canvas,$mul_x*($pdf_x+$pos-5)+$add_x/2, $pdf_y-7, $mul_x*($pdf_x+$pos+5)+$add_x, $pdf_y+7,1,"0:0:0:0","0:244:244:244",2);
}
}
}

sub pdf_gen_line_op {

my (
$self,
$id,
$canvas,
$pdf_x,
$pdf_y,
$add_x,
$mul_x,
$pos,
$op,
$qtype,
$switches,
) = @_;

if ($op =~ /^comp/) {
ONO::Lib::PDF::Draw->circle( $canvas,$mul_x*($pdf_x+$pos)+$add_x/2, $pdf_y, 3.5);
if ($switches =~ /c/ && $op =~ /^comp-(.*?)$/) {
ONO::Lib::PDF::Draw->text( $canvas,$mul_x*($pdf_x+$pos)+$add_x/2, $pdf_y+1, $1,"c",0,"M");
}
} else {
ONO::Lib::PDF::Draw->text_math_symbol($canvas,$mul_x*($pdf_x+$pos)+$add_x/2,$pdf_y,2.5,$op);
}

}

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

1;

__END__