From e2128fa5228c8ac9f8bfdac31eec111c406e2959 Mon Sep 17 00:00:00 2001 From: ywarnier Date: Sun, 27 Feb 2011 03:52:35 -0500 Subject: [PATCH 1/3] Added Excel question import from Dokeos 2 (initially developed by iflores, carefully reviewed for fixes and improvements) --- main/exercice/exercice.php | 4 +- main/exercice/exercise.class.php | 32 + main/exercice/question.class.php | 51 +- main/exercice/quiz_template.xls | Bin 0 -> 11776 bytes main/exercice/upload_exercise.php | 296 ++++++ main/img/icons/16/export_excel.png | Bin 0 -> 799 bytes main/img/icons/32/import_excel.png | Bin 0 -> 1965 bytes main/inc/lib/pear/excelreader/OLERead.inc | 271 +++++ main/inc/lib/pear/excelreader/reader.php | 1088 +++++++++++++++++++++ 9 files changed, 1737 insertions(+), 5 deletions(-) create mode 100755 main/exercice/quiz_template.xls create mode 100755 main/exercice/upload_exercise.php create mode 100644 main/img/icons/16/export_excel.png create mode 100644 main/img/icons/32/import_excel.png create mode 100755 main/inc/lib/pear/excelreader/OLERead.inc create mode 100755 main/inc/lib/pear/excelreader/reader.php diff --git a/main/exercice/exercice.php b/main/exercice/exercice.php index 7515e39626..6b286f7f21 100755 --- a/main/exercice/exercice.php +++ b/main/exercice/exercice.php @@ -263,7 +263,7 @@ if ($show == 'result' && $_REQUEST['comments'] == 'update' && ($is_allowedToEdit $message = str_replace("#url#", $url, $mess); $mess = $message; $headers = " MIME-Version: 1.0 \r\n"; - $headers .= "User-Agent: Dokeos/1.6"; + $headers .= "User-Agent: Chamilo/1.8"; $headers .= "Content-Transfer-Encoding: 7bit"; $headers .= 'From: ' . $from_name . ' <' . $from . '>' . "\r\n"; $headers = "From:$from_name\r\nReply-to: $to"; @@ -595,7 +595,7 @@ if ($is_allowedToEdit && $origin != 'learnpath') { echo '' . Display :: return_icon('import_hotpotatoes.png', get_lang('ImportHotPotatoesQuiz'),'','32').''; // link to import qti2 ... echo '' . Display :: return_icon('import_qti2.png', get_lang('ImportQtiQuiz'),'','32') .''; - //echo '' . Display :: return_icon('show_test_results.gif', get_lang('Results')) . get_lang('Results') . ''; + echo '' . Display :: return_icon('import_excel.png', get_lang('ImportExcelQuiz'),'','32') .''; } // the actions for the statistics diff --git a/main/exercice/exercise.class.php b/main/exercice/exercise.class.php index dcfd64eb4f..29b49b31b8 100755 --- a/main/exercice/exercise.class.php +++ b/main/exercice/exercise.class.php @@ -2616,6 +2616,38 @@ class Exercise {
'; return $html; } + /** + * Create a quiz from quiz data + * @param string Title + * @param int Time before it expires (in minutes) + * @param int Type of exercise + * @param int Whether it's randomly picked questions (1) or not (0) + * @param int Whether the exercise is visible to the user (1) or not (0) + * @param int Whether the results are show to the user (0) or not (1) + * @param int Maximum number of attempts (0 if no limit) + * @param int Feedback type + * @return int New exercise ID + */ + function create_quiz ($title, $expired_time = 0, $type = 2, $random = 0, $active = 1, $results_disabled = 0, $max_attempt = 0, $feedback = 3) { + $tbl_quiz = Database::get_course_table(TABLE_QUIZ_TEST); + $expired_time = filter_var($expired_time,FILTER_SANITIZE_NUMBER_INT); + $type = filter_var($type,FILTER_SANITIZE_NUMBER_INT); + $random = filter_var($random,FILTER_SANITIZE_NUMBER_INT); + $active = filter_var($active,FILTER_SANITIZE_NUMBER_INT); + $results_disabled = filter_var($results_disabled,FILTER_SANITIZE_NUMBER_INT); + $max_attempt = filter_var($max_attempt,FILTER_SANITIZE_NUMBER_INT); + $feedback = filter_var($feedback,FILTER_SANITIZE_NUMBER_INT); + $sid = api_get_session_id(); + // Save a new quiz + $sql = "INSERT INTO $tbl_quiz (title,type,random,active,results_disabled, ". + "max_attempt,start_time,end_time,feedback_type,expired_time, session_id) ". + " VALUES('".Database::escape_string($title)."',$type,$random,$active, ". + "$results_disabled,$max_attempt,'','',$feedback,$expired_time,$sid)"; + $rs = Database::query($sql); + $quiz_id = Database::get_last_insert_id(); + return $quiz_id; + } + } endif; ?> diff --git a/main/exercice/question.class.php b/main/exercice/question.class.php index 63157ae300..9d17f6aed2 100755 --- a/main/exercice/question.class.php +++ b/main/exercice/question.class.php @@ -1266,7 +1266,52 @@ abstract class Question echo Display::div(get_lang("Question").' '.($counter_label).' : '.$this->question, array('id'=>'question_title', 'class'=>'sectiontitle')); echo Display::div($this->description, array('id'=>'question_description')); } - + /** + * Create a question from a set of parameters + * @param int Quiz ID + * @param string Question name + * @param int Maximum result for the question + * @param int Type of question (see constants at beginning of question.class.php) + * @param int Question level/category + */ + function create_question ($quiz_id, $question_name, $max_score = 0, $type = 1, $level = 1) { + $tbl_quiz_question = Database::get_course_table(TABLE_QUIZ_QUESTION); + $tbl_quiz_rel_question = Database::get_course_table(TABLE_QUIZ_TEST_QUESTION); + $quiz_id = filter_var($quiz_id,FILTER_SANITIZE_NUMBER_INT); + $max_score = filter_var($max_score,FILTER_SANITIZE_NUMBER_FLOAT); + $type = filter_var($type,FILTER_SANITIZE_NUMBER_INT); + $level = filter_var($level,FILTER_SANITIZE_NUMBER_INT); + // Get the max position + $sql = "SELECT max(position) as max_position" + ." FROM $tbl_quiz_question q INNER JOIN $tbl_quiz_rel_question r" + ." ON q.id = r.question_id" + ." AND exercice_id = $quiz_id"; + $rs_max = Database::query($sql, __FILE__, __LINE__); + $row_max = Database::fetch_object($rs_max); + $max_position = $row_max->max_position +1; + + // Insert the new question + $sql = "INSERT INTO $tbl_quiz_question" + ." (question,ponderation,position,type,level) " + ." VALUES('".Database::escape_string($question_name)."'," + ." $max_score , $max_position, $type, $level)"; + error_log($sql); + $rs = Database::query($sql); + // Get the question ID + $question_id = Database::get_last_insert_id(); + // Get the max question_order + $sql = "SELECT max(question_order) as max_order " + ."FROM $tbl_quiz_rel_question WHERE exercice_id = $quiz_id "; + $rs_max_order = Database::query($sql); + $row_max_order = Database::fetch_object($rs_max_order); + $max_order = $row_max_order->max_order + 1; + // Attach questions to quiz + $sql = "INSERT INTO $tbl_quiz_rel_question " + ."(question_id,exercice_id,question_order)" + ." VALUES($question_id, $quiz_id, $max_order)"; + error_log($sql); + $rs = Database::query($sql); + return $question_id; + } } -endif; -?> \ No newline at end of file +endif; \ No newline at end of file diff --git a/main/exercice/quiz_template.xls b/main/exercice/quiz_template.xls new file mode 100755 index 0000000000000000000000000000000000000000..709b1d08b698c2ebcce10bb8367379a2d5e77474 GIT binary patch literal 11776 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 wgC63lgQvehyg7YN+`{;I9-S+x^B"; + +// Action handling +lp_upload_quiz_action_handling(); + +// Display the header +if ($origin != 'learnpath') { + //so we are not in learnpath tool + Display :: display_header($nameTools, get_lang('Exercise')); + if (isset ($_GET['message'])) { + if (in_array($_GET['message'], array ('ExerciseEdited'))) { + Display :: display_confirmation_message(get_lang($_GET['message'])); + } + } +} else { + echo ''; +} +// display the actions +echo '
'; +echo lp_upload_quiz_actions(); +echo '
'; + +// start the content div +echo '
'; +// the main content +lp_upload_quiz_main(); + +// close the content div +echo '
'; + +function lp_upload_quiz_actions() { + $lp_id = Security::remove_XSS($_GET['lp_id']); + $return = ""; + $return .= ''.Display::return_icon('back.png', get_lang('BackToExercisesList'),'','32').''; + $return .= '' . Display :: return_icon('new_exercice.png', get_lang('NewEx'),'','32').''; + $return .= '' . Display :: return_icon('new_question.png', get_lang('AddQ'),'','32').''; + $return .= '' . Display :: return_icon('import_hotpotatoes.png', get_lang('ImportHotPotatoesQuiz'),'','32').''; + // link to import qti2 ... + $return .= '' . Display :: return_icon('import_qti2.png', get_lang('ImportQtiQuiz'),'','32') .''; + $return .= '' . Display :: return_icon('import_excel.png', get_lang('ImportExcelQuiz'),'','32') .''; + return $return; +} + +function lp_upload_quiz_secondary_actions() { + $lp_id = Security::remove_XSS($_GET['lp_id']); + $return.= ''; + $return.='' . Display :: return_icon('reporting32.png', get_lang('Tracking')) . get_lang('Tracking') . ''; + return $return; +} + +function lp_upload_quiz_main() { + // Database table definition + global $_course; + $table_document = Database::get_course_table(TABLE_DOCUMENT, $_course['dbName']); + $propTable = Database::get_course_table(TABLE_ITEM_PROPERTY); + // variable initialisation + $lp_id = Security::remove_XSS($_GET['lp_id']); + + $form = new FormValidator('upload', 'POST', api_get_self() . '?' . api_get_cidreq() . '&lp_id=' . $lp_id, '', 'enctype="multipart/form-data"'); + $form->addElement('html', '

' .Display::return_icon('import_excel.png', get_lang('ImportExcelQuiz'),array('style'=>'margin-bottom:-2px;'),32). get_lang('ImportExcelQuiz') . '

'); + //button send document + $form->addElement('style_submit_button', 'submit_upload_quiz', get_lang('Validate'), 'class="upload"'); + $form->setDefaults($defaults); + + // Display the upload field + echo ''; + echo ''; + echo ''; + echo '
'; + echo ''.Display::return_icon('export_excel.png', get_lang('DownloadExcelTemplate'),null,16).get_lang('DownloadExcelTemplate').''; + echo ''; + echo '
'; + $form->display(); + echo '
'; +} + +/** + * Handles a given Excel spreadsheets as in the template provided + */ +function lp_upload_quiz_action_handling() { + global $charset, $_course, $_user, $debug; + if (!isset($_POST['submit_upload_quiz'])) { + return; + } + // Get the extension of the document. + $path_info = pathinfo($_FILES['user_upload_quiz']['name']); + // Check if the document is an Excel document + if ($path_info['extension'] != 'xls') { + return; + } + // Read the Excel document + $data = new Spreadsheet_Excel_Reader(); + // Set output Encoding. + $data->setOutputEncoding($charset); + // Reading the xls document. + $data->read($_FILES['user_upload_quiz']['tmp_name']); + // Variables + $quiz_index = 0; + $question_title_index = array(); + $question_name_index_init = array(); + $question_name_index_end = array(); + $score_index = array(); + $feedback_true_index = array(); + $feedback_false_index = array(); + $number_questions = 0; + // Reading all the first column items sequencially to create breakpoints + for ($i = 1; $i < $data->sheets[0]['numRows']; $i++) { + if ($data->sheets[0]['cells'][$i][1] == 'Quiz' && $i == 1) { + $quiz_index = $i; // Quiz title position, only occurs once + } elseif ($data->sheets[0]['cells'][$i][1] == 'Question') { + $question_title_index[] = $i; // Question title position line + $question_name_index_init[] = $i + 1; // Questions name 1st position line + $number_questions++; + } elseif ($data->sheets[0]['cells'][$i][1] == 'Score') { + $question_name_index_end[] = $i - 1; // Question name position + $score_index[] = $i; // Question score position + } elseif ($data->sheets[0]['cells'][$i][1] == 'FeedbackTrue') { + $feedback_true_index[] = $i; // FeedbackTrue position + } elseif ($data->sheets[0]['cells'][$i][1] == 'FeedbackFalse') { + $feedback_false_index[] = $i; // FeedbackFalse position + } + } + // Variables + $quiz = array(); + $question = array(); + $answer = array(); + $new_answer = array(); + $score_list = array(); + $feedback_true_list = array(); + $feedback_false_list = array(); + // Get questions + $k = $z = $q = $l = 0; + for ($i = 1; $i <= $data->sheets[0]['numRows']; $i++) { + if (is_array($data->sheets[0]['cells'][$i])) { + $column_data = $data->sheets[0]['cells'][$i]; + // Fill all column with data + for ($x = 1; $x <= $data->sheets[0]['numCols']; $x++) { + if (empty($column_data[$x])) { + $data->sheets[0]['cells'][$i][$x] = ''; + } + } + // Array filled with data + $column_data = $data->sheets[0]['cells'][$i]; + } else { + $column_data = ''; + } + // Fill quiz data + if ($quiz_index == $i) { // The title always in the first position + $quiz = $column_data; + } elseif (in_array($i, $question_title_index)) { + $question[$k] = $column_data; + $k++; + } elseif (in_array($i, $score_index)) { + $score_list[$z] = $column_data; + $z++; + } elseif (in_array($i, $feedback_true_index)) { + $feedback_true_list[$q] = $column_data; + $q++; + } elseif (in_array($i, $feedback_false_index)) { + $feedback_false_list[$l] = $column_data; + $l++; + } + } + // Get answers + for ($i = 0; $i < count($question_name_index_init); $i++) { + for ($j = $question_name_index_init[$i]; $j <= $question_name_index_end[$i]; $j++) { + if (is_array($data->sheets[0]['cells'][$j])) { + $column_data = $data->sheets[0]['cells'][$j]; + // Fill all column with data + for ($x = 1; $x <= $data->sheets[0]['numCols']; $x++) { + if (empty($column_data[$x])) { + $data->sheets[0]['cells'][$j][$x] = ''; + } + } + $column_data = $data->sheets[0]['cells'][$j]; + // Array filled of data + if (is_array($data->sheets[0]['cells'][$j]) && count($data->sheets[0]['cells'][$j]) > 0) { + $new_answer[$i][$j] = $data->sheets[0]['cells'][$j]; + } + } + } + } + $quiz_title = $quiz[2]; // Quiz title + if ($quiz_title != '') { + // Variables + $type = 2; + $random = $active = $results = $max_attempt = $expired_time = 0; + $feedback = 3; + // Quiz object + $quiz_object = new Exercise(); + $quiz_id = $quiz_object->create_quiz($quiz_title, $expired_time, $type, $random, $active, $results, $max_attempt, $feedback); + // insert into the item_property table + api_item_property_update($_course, TOOL_QUIZ, $quiz_id, 'QuizAdded', api_get_user_id()); + // Import questions + for ($i = 0; $i < $number_questions; $i++) { + // Create questions + $question_title = $question[$i][2]; // Question name + if ($question_title != '') { + $question_id = Question::create_question($quiz_id, $question_title); + } + $unique_answer = new UniqueAnswer(); + if (is_array($new_answer[$i])) { + $id = 1; + $answers_data = $new_answer[$i]; + foreach ($answers_data as $answer_data) { + $answer = $answer_data[2]; + $correct = 0; + $score = 0; + $comment = ''; + if (strtolower($answer_data[3]) == 'x') { + $correct = 1; + $score = $score_list[$i][3]; + } + if ($id == 1) { + $comment = $feedback_true_list[$i][2]; + } elseif ($id == 2) { + $comment = $feedback_false_list[$i][2]; + } + // Create answer + $unique_answer->create_answer($id, $question_id, $answer, $comment, $score, $correct); + $id++; + } + } + } + if (isset($_SESSION['lpobject'])) { + if ($debug > 0) { + error_log('New LP - SESSION[lpobject] is defined', 0); + } + $oLP = unserialize($_SESSION['lpobject']); + if (is_object($oLP)) { + if ($debug > 0) { + error_log('New LP - oLP is object', 0); + } + if ((empty($oLP->cc)) OR $oLP->cc != api_get_course_id()) { + if ($debug > 0) { + error_log('New LP - Course has changed, discard lp object', 0); + } + $oLP = null; + api_session_unregister('oLP'); + api_session_unregister('lpobject'); + } else { + $_SESSION['oLP'] = $oLP; + $lp_found = true; + } + } + } + if (isset($_SESSION['oLP']) && isset($_GET['lp_id'])) { + $previous = $_SESSION['oLP']->select_previous_item_id(); + $parent = 0; + // Add a Quiz as Lp Item + $_SESSION['oLP']->add_item($parent, $previous, TOOL_QUIZ, $quiz_id, $quiz_title, ''); + // Redirect to home page for add more content + header('location: ../newscorm/lp_controller.php?' . api_get_cidreq() . '&action=add_item&type=step&lp_id=' . Security::remove_XSS($_GET['lp_id']).'&session_id='.api_get_session_id()); + } else { + // header('location: exercice.php?' . api_get_cidreq()); + echo ''; + } + } +} \ No newline at end of file diff --git a/main/img/icons/16/export_excel.png b/main/img/icons/16/export_excel.png new file mode 100644 index 0000000000000000000000000000000000000000..e7193d2fd537b9870fac20f26a155b7f4d0d977b GIT binary patch literal 799 zcmV+)1K|9LP)Px#24YJ`L;(K){{a7>y{D4^000SaNLh0L01EH`01EH{Laa2H00007bV*G`2ipQ0 z2qO)L{-4$W00N&$L_t(I%YBkfOjKtShM#-q0>fbCnn1OnR{oke{TYy|@i%4BC83E4 zcB2Vtqb%x17fno)u9}c8+Py}N8)9%_a4{sP!MN~Wz%ZjlKS{z_zm^<9L-~GPN zg)&M|Px3C$bI$vo1Hjze+@FO)K|7AKM)`bR=W;ncHa50{_ml}BgxDMm2KkTxU0YlG zC>o7M-V4xL^Re=M->_|4M^(ygtnkNf-k zOLi;(rBn%^kPJT=#1ln?FHzb+NX7hOh9BDx8x<85Ivft41=>r1l?^m-Yx)|W+AVCW zsbezn9J~4xq?S0#1q{o?wrxX7DOXugN};u8BKeS}&%zwPbcCx9qMZ1>q*R~{=AAT`d#-Rl{X1t){l=Y{yA03XAhr<0GRhD_@Xi9SEmQ^# z1D}Yle>9 z+wp{t)*7W$Nm5E2$0=U{7y#QEnz#Pk{awo+_jc~tR~CI#Q&Z)6MYlBV-Da(|kxHeK d@p$|Rz$*`Ib7_97m4W~O002ovPDHLkV1kkAY8(In literal 0 HcmV?d00001 diff --git a/main/img/icons/32/import_excel.png b/main/img/icons/32/import_excel.png new file mode 100644 index 0000000000000000000000000000000000000000..4b4997a7e2d18c2c82249f0cab95e9a93d5f7c8a GIT binary patch literal 1965 zcmV;e2U7TnP)Px#24YJ`L;(K){{a7>y{D4^000SaNLh0L01EH`01EH{Laa2H00007bV*G`2ipQ0 z2m?B*#~ynC00%8eL_t(o!?l-vY?W6X$3N%X=icYuwinu4`aP(z3KXHu04HOP zxVg=lC|i_dGjWK~#1P`U5`y}NS#I}Z+^03sTVQe9oWu&%D|?cKX~S56v$)|&ry zXsro?fQpI=YHMqoX3d)Q$L-sg(&5EL^y7?|4ke(SDqeDk;Ym%d&_@qf{oUFrK0BS}&bfuF%=p ziR-$Ql$5kIG&CI8v17-KyX{){10aMz2!WFwpmX377%+&D|BV?Ir8O#0>#{yYn2 zJc3aM*L8`<<47r&q*AGMz>miSpp?1?gcK44wD+Ckbk7O0UIt5AXl+nh4?h8;1=@ht zim(WCx%Vpb>*iCNsKFT;L`sQm+f-Fmm5$56SgD1Cv)w1?ORra#?7No*z? z_x_0Hx<*z$+=5S@14sWsTj#%7)zr+i%BkdC4=`kOmZY18xF8$}V=Ehga5#*Va>7D1 zQcw!MKhklKs2!)ObQ*uX@DAVJw~3qSUfR2^@y(yT#(U@5DVrK6?Wf7B9O)oS(o2(9 z?ywyJwrvxMM2JKp2qBm-2=9)8yq_g7n(}ypZJ*o1)_1?c?@s-M)5oS@hl}{q3(wJK zdgyZ;@<9$yxkw9CE<#9J+@0b|DejvEcd&5#^FX?vhU!K(e*Ehk>)C~zGKKX|y@YGu zFMmNQ7V)60!?KY2d~MuLGL2u3zFRYh99u;(~^Dd zukuX8R?6*%NO~!*g|0E^rpS0{`UY>IQE-=ACj=0&rIHdXOQ7{|u!Kg1=+1p_awUI= zO)EF^ktsR09obAwEasUo{2f-+IbrS2<~Q^Cs%*HT+qi5K`Ioz{2&EYbA)vZ>*s$o^mcJ$>SDGfOsn?W0Hq z28i1*kcLy26p^r?^{tB(d;QeRt6*BFp5{fBc%DKEi4+oL6as-23gN4ObT)fWzj$vD z4h%S@E!7WwqP{P2bI9xOOBzZnf!1*RD*Wk$rn}t-M-m>&^6s`WmbcX5xdHtHLl~nc zY|{!Q*cdZ51EzBWV#;RP*TgfGb7pfZ1J`|M>w}X$aLboOsw{j9j0zJ-3(pVkSmb^! zd*L~544C9*Gt_a`mtjd(!VP!0l-HHRj8d?QLRiHiWGsXqXnaqR$_8ky?uhd7L@8Ae zGj1Jt;<0&U{lym3OCc;k0Lnl*4?|IbZv(c4kmfeE1`y*iFj^l9g$RX00HJXKT)5mP z6Qw@2(*%|T-#|`5%7d5-nJ5T5gs*bsb9r)}8uz|8`dBY?SB~S*-QDfo1GF%~3eOS` ze{y5{tfm#S0xk5d3^L=1a4M_(Tp)BdFJw{bV)FUgherror = 1; + return false; + } + + $this->data = @file_get_contents($sFileName); + if (!$this->data) { + $this->error = 1; + return false; + } + //echo IDENTIFIER_OLE; + //echo 'start'; + if (substr($this->data, 0, 8) != IDENTIFIER_OLE) { + $this->error = 1; + return false; + } + $this->numBigBlockDepotBlocks = GetInt4d($this->data, NUM_BIG_BLOCK_DEPOT_BLOCKS_POS); + $this->sbdStartBlock = GetInt4d($this->data, SMALL_BLOCK_DEPOT_BLOCK_POS); + $this->rootStartBlock = GetInt4d($this->data, ROOT_START_BLOCK_POS); + $this->extensionBlock = GetInt4d($this->data, EXTENSION_BLOCK_POS); + $this->numExtensionBlocks = GetInt4d($this->data, NUM_EXTENSION_BLOCK_POS); + + /* + echo $this->numBigBlockDepotBlocks." "; + echo $this->sbdStartBlock." "; + echo $this->rootStartBlock." "; + echo $this->extensionBlock." "; + echo $this->numExtensionBlocks." "; + */ + //echo "sbdStartBlock = $this->sbdStartBlock\n"; + $bigBlockDepotBlocks = array(); + $pos = BIG_BLOCK_DEPOT_BLOCKS_POS; + // echo "pos = $pos"; + $bbdBlocks = $this->numBigBlockDepotBlocks; + + if ($this->numExtensionBlocks != 0) { + $bbdBlocks = (BIG_BLOCK_SIZE - BIG_BLOCK_DEPOT_BLOCKS_POS)/4; + } + + for ($i = 0; $i < $bbdBlocks; $i++) { + $bigBlockDepotBlocks[$i] = GetInt4d($this->data, $pos); + $pos += 4; + } + + + for ($j = 0; $j < $this->numExtensionBlocks; $j++) { + $pos = ($this->extensionBlock + 1) * BIG_BLOCK_SIZE; + $blocksToRead = min($this->numBigBlockDepotBlocks - $bbdBlocks, BIG_BLOCK_SIZE / 4 - 1); + + for ($i = $bbdBlocks; $i < $bbdBlocks + $blocksToRead; $i++) { + $bigBlockDepotBlocks[$i] = GetInt4d($this->data, $pos); + $pos += 4; + } + + $bbdBlocks += $blocksToRead; + if ($bbdBlocks < $this->numBigBlockDepotBlocks) { + $this->extensionBlock = GetInt4d($this->data, $pos); + } + } + + // var_dump($bigBlockDepotBlocks); + + // readBigBlockDepot + $pos = 0; + $index = 0; + $this->bigBlockChain = array(); + + for ($i = 0; $i < $this->numBigBlockDepotBlocks; $i++) { + $pos = ($bigBlockDepotBlocks[$i] + 1) * BIG_BLOCK_SIZE; + //echo "pos = $pos"; + for ($j = 0 ; $j < BIG_BLOCK_SIZE / 4; $j++) { + $this->bigBlockChain[$index] = GetInt4d($this->data, $pos); + $pos += 4 ; + $index++; + } + } + + //var_dump($this->bigBlockChain); + //echo '=====2'; + // readSmallBlockDepot(); + $pos = 0; + $index = 0; + $sbdBlock = $this->sbdStartBlock; + $this->smallBlockChain = array(); + + while ($sbdBlock != -2) { + + $pos = ($sbdBlock + 1) * BIG_BLOCK_SIZE; + + for ($j = 0; $j < BIG_BLOCK_SIZE / 4; $j++) { + $this->smallBlockChain[$index] = GetInt4d($this->data, $pos); + $pos += 4; + $index++; + } + + $sbdBlock = $this->bigBlockChain[$sbdBlock]; + } + + + // readData(rootStartBlock) + $block = $this->rootStartBlock; + $pos = 0; + $this->entry = $this->__readData($block); + + /* + while ($block != -2) { + $pos = ($block + 1) * BIG_BLOCK_SIZE; + $this->entry = $this->entry.substr($this->data, $pos, BIG_BLOCK_SIZE); + $block = $this->bigBlockChain[$block]; + } + */ + //echo '==='.$this->entry."==="; + $this->__readPropertySets(); + + } + + function __readData($bl) { + $block = $bl; + $pos = 0; + $data = ''; + + while ($block != -2) { + $pos = ($block + 1) * BIG_BLOCK_SIZE; + $data = $data.substr($this->data, $pos, BIG_BLOCK_SIZE); + //echo "pos = $pos data=$data\n"; + $block = $this->bigBlockChain[$block]; + } + return $data; + } + + function __readPropertySets(){ + $offset = 0; + //var_dump($this->entry); + while ($offset < strlen($this->entry)) { + $d = substr($this->entry, $offset, PROPERTY_STORAGE_BLOCK_SIZE); + + $nameSize = ord($d[SIZE_OF_NAME_POS]) | (ord($d[SIZE_OF_NAME_POS+1]) << 8); + + $type = ord($d[TYPE_POS]); + //$maxBlock = strlen($d) / BIG_BLOCK_SIZE - 1; + + $startBlock = GetInt4d($d, START_BLOCK_POS); + $size = GetInt4d($d, SIZE_POS); + + $name = ''; + for ($i = 0; $i < $nameSize ; $i++) { + $name .= $d[$i]; + } + + $name = str_replace("\x00", "", $name); + + $this->props[] = array ( + 'name' => $name, + 'type' => $type, + 'startBlock' => $startBlock, + 'size' => $size); + + if (($name == "Workbook") || ($name == "Book")) { + $this->wrkbook = count($this->props) - 1; + } + + if ($name == "Root Entry") { + $this->rootentry = count($this->props) - 1; + } + + //echo "name ==$name=\n"; + + + $offset += PROPERTY_STORAGE_BLOCK_SIZE; + } + + } + + + function getWorkBook(){ + if ($this->props[$this->wrkbook]['size'] < SMALL_BLOCK_THRESHOLD){ +// getSmallBlockStream(PropertyStorage ps) + + $rootdata = $this->__readData($this->props[$this->rootentry]['startBlock']); + + $streamData = ''; + $block = $this->props[$this->wrkbook]['startBlock']; + //$count = 0; + $pos = 0; + while ($block != -2) { + $pos = $block * SMALL_BLOCK_SIZE; + $streamData .= substr($rootdata, $pos, SMALL_BLOCK_SIZE); + + $block = $this->smallBlockChain[$block]; + } + + return $streamData; + + + }else{ + + $numBlocks = $this->props[$this->wrkbook]['size'] / BIG_BLOCK_SIZE; + if ($this->props[$this->wrkbook]['size'] % BIG_BLOCK_SIZE != 0) { + $numBlocks++; + } + + if ($numBlocks == 0) return ''; + + //echo "numBlocks = $numBlocks\n"; + //byte[] streamData = new byte[numBlocks * BIG_BLOCK_SIZE]; + //print_r($this->wrkbook); + $streamData = ''; + $block = $this->props[$this->wrkbook]['startBlock']; + //$count = 0; + $pos = 0; + //echo "block = $block"; + while ($block != -2) { + $pos = ($block + 1) * BIG_BLOCK_SIZE; + $streamData .= substr($this->data, $pos, BIG_BLOCK_SIZE); + $block = $this->bigBlockChain[$block]; + } + //echo 'stream'.$streamData; + return $streamData; + } + } + +} +?> \ No newline at end of file diff --git a/main/inc/lib/pear/excelreader/reader.php b/main/inc/lib/pear/excelreader/reader.php new file mode 100755 index 0000000000..da27dc88ab --- /dev/null +++ b/main/inc/lib/pear/excelreader/reader.php @@ -0,0 +1,1088 @@ + +* @license http://www.php.net/license/3_0.txt PHP License 3.0 +* @version CVS: $Id: reader.php 19 2007-03-13 12:42:41Z shangxiao $ +* @link http://pear.php.net/package/Spreadsheet_Excel_Reader +* @see OLE, Spreadsheet_Excel_Writer +*/ + + +//require_once 'PEAR.php'; +require_once 'OLERead.inc'; +//require_once 'OLE.php'; + +define('SPREADSHEET_EXCEL_READER_BIFF8', 0x600); +define('SPREADSHEET_EXCEL_READER_BIFF7', 0x500); +define('SPREADSHEET_EXCEL_READER_WORKBOOKGLOBALS', 0x5); +define('SPREADSHEET_EXCEL_READER_WORKSHEET', 0x10); + +define('SPREADSHEET_EXCEL_READER_TYPE_BOF', 0x809); +define('SPREADSHEET_EXCEL_READER_TYPE_EOF', 0x0a); +define('SPREADSHEET_EXCEL_READER_TYPE_BOUNDSHEET', 0x85); +define('SPREADSHEET_EXCEL_READER_TYPE_DIMENSION', 0x200); +define('SPREADSHEET_EXCEL_READER_TYPE_ROW', 0x208); +define('SPREADSHEET_EXCEL_READER_TYPE_DBCELL', 0xd7); +define('SPREADSHEET_EXCEL_READER_TYPE_FILEPASS', 0x2f); +define('SPREADSHEET_EXCEL_READER_TYPE_NOTE', 0x1c); +define('SPREADSHEET_EXCEL_READER_TYPE_TXO', 0x1b6); +define('SPREADSHEET_EXCEL_READER_TYPE_RK', 0x7e); +define('SPREADSHEET_EXCEL_READER_TYPE_RK2', 0x27e); +define('SPREADSHEET_EXCEL_READER_TYPE_MULRK', 0xbd); +define('SPREADSHEET_EXCEL_READER_TYPE_MULBLANK', 0xbe); +define('SPREADSHEET_EXCEL_READER_TYPE_INDEX', 0x20b); +define('SPREADSHEET_EXCEL_READER_TYPE_SST', 0xfc); +define('SPREADSHEET_EXCEL_READER_TYPE_EXTSST', 0xff); +define('SPREADSHEET_EXCEL_READER_TYPE_CONTINUE', 0x3c); +define('SPREADSHEET_EXCEL_READER_TYPE_LABEL', 0x204); +define('SPREADSHEET_EXCEL_READER_TYPE_LABELSST', 0xfd); +define('SPREADSHEET_EXCEL_READER_TYPE_NUMBER', 0x203); +define('SPREADSHEET_EXCEL_READER_TYPE_NAME', 0x18); +define('SPREADSHEET_EXCEL_READER_TYPE_ARRAY', 0x221); +define('SPREADSHEET_EXCEL_READER_TYPE_STRING', 0x207); +define('SPREADSHEET_EXCEL_READER_TYPE_FORMULA', 0x406); +define('SPREADSHEET_EXCEL_READER_TYPE_FORMULA2', 0x6); +define('SPREADSHEET_EXCEL_READER_TYPE_FORMAT', 0x41e); +define('SPREADSHEET_EXCEL_READER_TYPE_XF', 0xe0); +define('SPREADSHEET_EXCEL_READER_TYPE_BOOLERR', 0x205); +define('SPREADSHEET_EXCEL_READER_TYPE_UNKNOWN', 0xffff); +define('SPREADSHEET_EXCEL_READER_TYPE_NINETEENFOUR', 0x22); +define('SPREADSHEET_EXCEL_READER_TYPE_MERGEDCELLS', 0xE5); + +define('SPREADSHEET_EXCEL_READER_UTCOFFSETDAYS' , 25569); +define('SPREADSHEET_EXCEL_READER_UTCOFFSETDAYS1904', 24107); +define('SPREADSHEET_EXCEL_READER_MSINADAY', 86400); +//define('SPREADSHEET_EXCEL_READER_MSINADAY', 24 * 60 * 60); + +//define('SPREADSHEET_EXCEL_READER_DEF_NUM_FORMAT', "%.2f"); +define('SPREADSHEET_EXCEL_READER_DEF_NUM_FORMAT', "%s"); + + +/* +* Place includes, constant defines and $_GLOBAL settings here. +* Make sure they have appropriate docblocks to avoid phpDocumentor +* construing they are documented by the page-level docblock. +*/ + +/** +* A class for reading Microsoft Excel Spreadsheets. +* +* Originally developed by Vadim Tkachenko under the name PHPExcelReader. +* (http://sourceforge.net/projects/phpexcelreader) +* Based on the Java version by Andy Khan (http://www.andykhan.com). Now +* maintained by David Sanders. Reads only Biff 7 and Biff 8 formats. +* +* @category Spreadsheet +* @package Spreadsheet_Excel_Reader +* @author Vadim Tkachenko +* @copyright 1997-2005 The PHP Group +* @license http://www.php.net/license/3_0.txt PHP License 3.0 +* @version Release: @package_version@ +* @link http://pear.php.net/package/PackageName +* @see OLE, Spreadsheet_Excel_Writer +*/ +class Spreadsheet_Excel_Reader +{ + /** + * Array of worksheets found + * + * @var array + * @access public + */ + var $boundsheets = array(); + + /** + * Array of format records found + * + * @var array + * @access public + */ + var $formatRecords = array(); + + /** + * todo + * + * @var array + * @access public + */ + var $sst = array(); + + /** + * Array of worksheets + * + * The data is stored in 'cells' and the meta-data is stored in an array + * called 'cellsInfo' + * + * Example: + * + * $sheets --> 'cells' --> row --> column --> Interpreted value + * --> 'cellsInfo' --> row --> column --> 'type' - Can be 'date', 'number', or 'unknown' + * --> 'raw' - The raw data that Excel stores for that data cell + * + * @var array + * @access public + */ + var $sheets = array(); + + /** + * The data returned by OLE + * + * @var string + * @access public + */ + var $data; + + /** + * OLE object for reading the file + * + * @var OLE object + * @access private + */ + var $_ole; + + /** + * Default encoding + * + * @var string + * @access private + */ + var $_defaultEncoding; + + /** + * Default number format + * + * @var integer + * @access private + */ + var $_defaultFormat = SPREADSHEET_EXCEL_READER_DEF_NUM_FORMAT; + + /** + * todo + * List of formats to use for each column + * + * @var array + * @access private + */ + var $_columnsFormat = array(); + + /** + * todo + * + * @var integer + * @access private + */ + var $_rowoffset = 1; + + /** + * todo + * + * @var integer + * @access private + */ + var $_coloffset = 1; + + /** + * List of default date formats used by Excel + * + * @var array + * @access public + */ + var $dateFormats = array ( + 0xe => "d/m/Y", + 0xf => "d-M-Y", + 0x10 => "d-M", + 0x11 => "M-Y", + 0x12 => "h:i a", + 0x13 => "h:i:s a", + 0x14 => "H:i", + 0x15 => "H:i:s", + 0x16 => "d/m/Y H:i", + 0x2d => "i:s", + 0x2e => "H:i:s", + 0x2f => "i:s.S"); + + /** + * Default number formats used by Excel + * + * @var array + * @access public + */ + var $numberFormats = array( + 0x1 => "%1.0f", // "0" + 0x2 => "%1.2f", // "0.00", + 0x3 => "%1.0f", //"#,##0", + 0x4 => "%1.2f", //"#,##0.00", + 0x5 => "%1.0f", /*"$#,##0;($#,##0)",*/ + 0x6 => '$%1.0f', /*"$#,##0;($#,##0)",*/ + 0x7 => '$%1.2f', //"$#,##0.00;($#,##0.00)", + 0x8 => '$%1.2f', //"$#,##0.00;($#,##0.00)", + 0x9 => '%1.0f%%', // "0%" + 0xa => '%1.2f%%', // "0.00%" + 0xb => '%1.2f', // 0.00E00", + 0x25 => '%1.0f', // "#,##0;(#,##0)", + 0x26 => '%1.0f', //"#,##0;(#,##0)", + 0x27 => '%1.2f', //"#,##0.00;(#,##0.00)", + 0x28 => '%1.2f', //"#,##0.00;(#,##0.00)", + 0x29 => '%1.0f', //"#,##0;(#,##0)", + 0x2a => '$%1.0f', //"$#,##0;($#,##0)", + 0x2b => '%1.2f', //"#,##0.00;(#,##0.00)", + 0x2c => '$%1.2f', //"$#,##0.00;($#,##0.00)", + 0x30 => '%1.0f'); //"##0.0E0"; + + // }}} + // {{{ Spreadsheet_Excel_Reader() + + /** + * Constructor + * + * Some basic initialisation + */ + function Spreadsheet_Excel_Reader() + { + $this->_ole =& new OLERead(); + $this->setUTFEncoder('iconv'); + } + + // }}} + // {{{ setOutputEncoding() + + /** + * Set the encoding method + * + * @param string Encoding to use + * @access public + */ + function setOutputEncoding($encoding) + { + $this->_defaultEncoding = $encoding; + } + + // }}} + // {{{ setUTFEncoder() + + /** + * $encoder = 'iconv' or 'mb' + * set iconv if you would like use 'iconv' for encode UTF-16LE to your encoding + * set mb if you would like use 'mb_convert_encoding' for encode UTF-16LE to your encoding + * + * @access public + * @param string Encoding type to use. Either 'iconv' or 'mb' + */ + function setUTFEncoder($encoder = 'iconv') + { + $this->_encoderFunction = ''; + + if ($encoder == 'iconv') { + $this->_encoderFunction = function_exists('iconv') ? 'iconv' : ''; + } elseif ($encoder == 'mb') { + $this->_encoderFunction = function_exists('mb_convert_encoding') ? + 'mb_convert_encoding' : + ''; + } + } + + // }}} + // {{{ setRowColOffset() + + /** + * todo + * + * @access public + * @param offset + */ + function setRowColOffset($iOffset) + { + $this->_rowoffset = $iOffset; + $this->_coloffset = $iOffset; + } + + // }}} + // {{{ setDefaultFormat() + + /** + * Set the default number format + * + * @access public + * @param Default format + */ + function setDefaultFormat($sFormat) + { + $this->_defaultFormat = $sFormat; + } + + // }}} + // {{{ setColumnFormat() + + /** + * Force a column to use a certain format + * + * @access public + * @param integer Column number + * @param string Format + */ + function setColumnFormat($column, $sFormat) + { + $this->_columnsFormat[$column] = $sFormat; + } + + + // }}} + // {{{ read() + + /** + * Read the spreadsheet file using OLE, then parse + * + * @access public + * @param filename + * @todo return a valid value + */ + function read($sFileName) + { + /* + require_once 'OLE.php'; + $ole = new OLE(); + $ole->read($sFileName); + + foreach ($ole->_list as $i => $pps) { + if (($pps->Name == 'Workbook' || $pps->Name == 'Book') && + $pps->Size >= SMALL_BLOCK_THRESHOLD) { + + $this->data = $ole->getData($i, 0, $ole->getDataLength($i)); + } elseif ($pps->Name == 'Root Entry') { + $this->data = $ole->getData($i, 0, $ole->getDataLength($i)); + } + //var_dump(strlen($ole->getData($i, 0, $ole->getDataLength($i))), $pps->Name, md5($this->data), $ole->getDataLength($i)); + } +//exit; + $this->_parse(); + + return sizeof($this->sheets) > 0; + */ + + $res = $this->_ole->read($sFileName); + + // oops, something goes wrong (Darko Miljanovic) + if($res === false) { + // check error code + if($this->_ole->error == 1) { + // bad file + //die('The filename ' . $sFileName . ' is not readable'); + Display::display_header(''); + Display::display_error_message(get_lang('XLSFileNotValid')); + Display::display_footer(); + exit; + } + // check other error codes here (eg bad fileformat, etc...) + } + + $this->data = $this->_ole->getWorkBook(); + + + /* + $res = $this->_ole->read($sFileName); + + if ($this->isError($res)) { +// var_dump($res); + return $this->raiseError($res); + } + + $total = $this->_ole->ppsTotal(); + for ($i = 0; $i < $total; $i++) { + if ($this->_ole->isFile($i)) { + $type = unpack("v", $this->_ole->getData($i, 0, 2)); + if ($type[''] == 0x0809) { // check if it's a BIFF stream + $this->_index = $i; + $this->data = $this->_ole->getData($i, 0, $this->_ole->getDataLength($i)); + break; + } + } + } + + if ($this->_index === null) { + return $this->raiseError("$file doesn't seem to be an Excel file"); + } + + */ + + //echo "data =".$this->data; + //$this->readRecords(); + $this->_parse(); + } + + + // }}} + // {{{ _parse() + + /** + * Parse a workbook + * + * @access private + * @return bool + */ + function _parse() + { + $pos = 0; + + $code = ord($this->data[$pos]) | ord($this->data[$pos+1])<<8; + $length = ord($this->data[$pos+2]) | ord($this->data[$pos+3])<<8; + + $version = ord($this->data[$pos + 4]) | ord($this->data[$pos + 5])<<8; + $substreamType = ord($this->data[$pos + 6]) | ord($this->data[$pos + 7])<<8; + //echo "Start parse code=".base_convert($code,10,16)." version=".base_convert($version,10,16)." substreamType=".base_convert($substreamType,10,16).""."\n"; + + if (($version != SPREADSHEET_EXCEL_READER_BIFF8) && + ($version != SPREADSHEET_EXCEL_READER_BIFF7)) { + return false; + } + + if ($substreamType != SPREADSHEET_EXCEL_READER_WORKBOOKGLOBALS){ + return false; + } + + //print_r($rec); + $pos += $length + 4; + + $code = ord($this->data[$pos]) | ord($this->data[$pos+1])<<8; + $length = ord($this->data[$pos+2]) | ord($this->data[$pos+3])<<8; + + while ($code != SPREADSHEET_EXCEL_READER_TYPE_EOF) { + switch ($code) { + case SPREADSHEET_EXCEL_READER_TYPE_SST: + //echo "Type_SST\n"; + $spos = $pos + 4; + $limitpos = $spos + $length; + $uniqueStrings = $this->_GetInt4d($this->data, $spos+4); + $spos += 8; + for ($i = 0; $i < $uniqueStrings; $i++) { + // Read in the number of characters + if ($spos == $limitpos) { + $opcode = ord($this->data[$spos]) | ord($this->data[$spos+1])<<8; + $conlength = ord($this->data[$spos+2]) | ord($this->data[$spos+3])<<8; + if ($opcode != 0x3c) { + return -1; + } + $spos += 4; + $limitpos = $spos + $conlength; + } + $numChars = ord($this->data[$spos]) | (ord($this->data[$spos+1]) << 8); + //echo "i = $i pos = $pos numChars = $numChars "; + $spos += 2; + $optionFlags = ord($this->data[$spos]); + $spos++; + $asciiEncoding = (($optionFlags & 0x01) == 0) ; + $extendedString = ( ($optionFlags & 0x04) != 0); + + // See if string contains formatting information + $richString = ( ($optionFlags & 0x08) != 0); + + if ($richString) { + // Read in the crun + $formattingRuns = ord($this->data[$spos]) | (ord($this->data[$spos+1]) << 8); + $spos += 2; + } + + if ($extendedString) { + // Read in cchExtRst + $extendedRunLength = $this->_GetInt4d($this->data, $spos); + $spos += 4; + } + + $len = ($asciiEncoding)? $numChars : $numChars*2; + if ($spos + $len < $limitpos) { + $retstr = substr($this->data, $spos, $len); + $spos += $len; + }else{ + // found countinue + $retstr = substr($this->data, $spos, $limitpos - $spos); + $bytesRead = $limitpos - $spos; + $charsLeft = $numChars - (($asciiEncoding) ? $bytesRead : ($bytesRead / 2)); + $spos = $limitpos; + + while ($charsLeft > 0){ + $opcode = ord($this->data[$spos]) | ord($this->data[$spos+1])<<8; + $conlength = ord($this->data[$spos+2]) | ord($this->data[$spos+3])<<8; + if ($opcode != 0x3c) { + return -1; + } + $spos += 4; + $limitpos = $spos + $conlength; + $option = ord($this->data[$spos]); + $spos += 1; + if ($asciiEncoding && ($option == 0)) { + $len = min($charsLeft, $limitpos - $spos); // min($charsLeft, $conlength); + $retstr .= substr($this->data, $spos, $len); + $charsLeft -= $len; + $asciiEncoding = true; + }elseif (!$asciiEncoding && ($option != 0)){ + $len = min($charsLeft * 2, $limitpos - $spos); // min($charsLeft, $conlength); + $retstr .= substr($this->data, $spos, $len); + $charsLeft -= $len/2; + $asciiEncoding = false; + }elseif (!$asciiEncoding && ($option == 0)) { + // Bummer - the string starts off as Unicode, but after the + // continuation it is in straightforward ASCII encoding + $len = min($charsLeft, $limitpos - $spos); // min($charsLeft, $conlength); + for ($j = 0; $j < $len; $j++) { + $retstr .= $this->data[$spos + $j].chr(0); + } + $charsLeft -= $len; + $asciiEncoding = false; + }else{ + $newstr = ''; + for ($j = 0; $j < strlen($retstr); $j++) { + $newstr = $retstr[$j].chr(0); + } + $retstr = $newstr; + $len = min($charsLeft * 2, $limitpos - $spos); // min($charsLeft, $conlength); + $retstr .= substr($this->data, $spos, $len); + $charsLeft -= $len/2; + $asciiEncoding = false; + //echo "Izavrat\n"; + } + $spos += $len; + + } + } + $retstr = ($asciiEncoding) ? $retstr : $this->_encodeUTF16($retstr); +// echo "Str $i = $retstr\n"; + if ($richString){ + $spos += 4 * $formattingRuns; + } + + // For extended strings, skip over the extended string data + if ($extendedString) { + $spos += $extendedRunLength; + } + //if ($retstr == 'Derby'){ + // echo "bb\n"; + //} + $this->sst[]=$retstr; + } + /*$continueRecords = array(); + while ($this->getNextCode() == Type_CONTINUE) { + $continueRecords[] = &$this->nextRecord(); + } + //echo " 1 Type_SST\n"; + $this->shareStrings = new SSTRecord($r, $continueRecords); + //print_r($this->shareStrings->strings); + */ + // echo 'SST read: '.($time_end-$time_start)."\n"; + break; + + case SPREADSHEET_EXCEL_READER_TYPE_FILEPASS: + return false; + break; + case SPREADSHEET_EXCEL_READER_TYPE_NAME: + //echo "Type_NAME\n"; + break; + case SPREADSHEET_EXCEL_READER_TYPE_FORMAT: + $indexCode = ord($this->data[$pos+4]) | ord($this->data[$pos+5]) << 8; + + if ($version == SPREADSHEET_EXCEL_READER_BIFF8) { + $numchars = ord($this->data[$pos+6]) | ord($this->data[$pos+7]) << 8; + if (ord($this->data[$pos+8]) == 0){ + $formatString = substr($this->data, $pos+9, $numchars); + } else { + $formatString = substr($this->data, $pos+9, $numchars*2); + } + } else { + $numchars = ord($this->data[$pos+6]); + $formatString = substr($this->data, $pos+7, $numchars*2); + } + + $this->formatRecords[$indexCode] = $formatString; + // echo "Type.FORMAT\n"; + break; + case SPREADSHEET_EXCEL_READER_TYPE_XF: + //global $dateFormats, $numberFormats; + $indexCode = ord($this->data[$pos+6]) | ord($this->data[$pos+7]) << 8; + //echo "\nType.XF ".count($this->formatRecords['xfrecords'])." $indexCode "; + if (array_key_exists($indexCode, $this->dateFormats)) { + //echo "isdate ".$dateFormats[$indexCode]; + $this->formatRecords['xfrecords'][] = array( + 'type' => 'date', + 'format' => $this->dateFormats[$indexCode] + ); + }elseif (array_key_exists($indexCode, $this->numberFormats)) { + //echo "isnumber ".$this->numberFormats[$indexCode]; + $this->formatRecords['xfrecords'][] = array( + 'type' => 'number', + 'format' => $this->numberFormats[$indexCode] + ); + }else{ + $isdate = FALSE; + if ($indexCode > 0){ + if (isset($this->formatRecords[$indexCode])) + $formatstr = $this->formatRecords[$indexCode]; + //echo '.other.'; + //echo "\ndate-time=$formatstr=\n"; + if ($formatstr) + if (preg_match("/[^hmsday\/\-:\s]/i", $formatstr) == 0) { // found day and time format + $isdate = TRUE; + $formatstr = str_replace('mm', 'i', $formatstr); + $formatstr = str_replace('h', 'H', $formatstr); + //echo "\ndate-time $formatstr \n"; + } + } + + if ($isdate){ + $this->formatRecords['xfrecords'][] = array( + 'type' => 'date', + 'format' => $formatstr, + ); + }else{ + $this->formatRecords['xfrecords'][] = array( + 'type' => 'other', + 'format' => '', + 'code' => $indexCode + ); + } + } + //echo "\n"; + break; + case SPREADSHEET_EXCEL_READER_TYPE_NINETEENFOUR: + //echo "Type.NINETEENFOUR\n"; + $this->nineteenFour = (ord($this->data[$pos+4]) == 1); + break; + case SPREADSHEET_EXCEL_READER_TYPE_BOUNDSHEET: + //echo "Type.BOUNDSHEET\n"; + $rec_offset = $this->_GetInt4d($this->data, $pos+4); + $rec_typeFlag = ord($this->data[$pos+8]); + $rec_visibilityFlag = ord($this->data[$pos+9]); + $rec_length = ord($this->data[$pos+10]); + + if ($version == SPREADSHEET_EXCEL_READER_BIFF8){ + $chartype = ord($this->data[$pos+11]); + if ($chartype == 0){ + $rec_name = substr($this->data, $pos+12, $rec_length); + } else { + $rec_name = $this->_encodeUTF16(substr($this->data, $pos+12, $rec_length*2)); + } + }elseif ($version == SPREADSHEET_EXCEL_READER_BIFF7){ + $rec_name = substr($this->data, $pos+11, $rec_length); + } + $this->boundsheets[] = array('name'=>$rec_name, + 'offset'=>$rec_offset); + + break; + + } + + //echo "Code = ".base_convert($r['code'],10,16)."\n"; + $pos += $length + 4; + $code = ord($this->data[$pos]) | ord($this->data[$pos+1])<<8; + $length = ord($this->data[$pos+2]) | ord($this->data[$pos+3])<<8; + + //$r = &$this->nextRecord(); + //echo "1 Code = ".base_convert($r['code'],10,16)."\n"; + } + + foreach ($this->boundsheets as $key=>$val){ + $this->sn = $key; + $this->_parsesheet($val['offset']); + } + return true; + + } + + /** + * Parse a worksheet + * + * @access private + * @param todo + * @todo fix return codes + */ + function _parsesheet($spos) + { + $cont = true; + // read BOF + $code = ord($this->data[$spos]) | ord($this->data[$spos+1])<<8; + $length = ord($this->data[$spos+2]) | ord($this->data[$spos+3])<<8; + + $version = ord($this->data[$spos + 4]) | ord($this->data[$spos + 5])<<8; + $substreamType = ord($this->data[$spos + 6]) | ord($this->data[$spos + 7])<<8; + + if (($version != SPREADSHEET_EXCEL_READER_BIFF8) && ($version != SPREADSHEET_EXCEL_READER_BIFF7)) { + return -1; + } + + if ($substreamType != SPREADSHEET_EXCEL_READER_WORKSHEET){ + return -2; + } + //echo "Start parse code=".base_convert($code,10,16)." version=".base_convert($version,10,16)." substreamType=".base_convert($substreamType,10,16).""."\n"; + $spos += $length + 4; + //var_dump($this->formatRecords); + //echo "code $code $length"; + while($cont) { + //echo "mem= ".memory_get_usage()."\n"; +// $r = &$this->file->nextRecord(); + $lowcode = ord($this->data[$spos]); + if ($lowcode == SPREADSHEET_EXCEL_READER_TYPE_EOF) break; + $code = $lowcode | ord($this->data[$spos+1])<<8; + $length = ord($this->data[$spos+2]) | ord($this->data[$spos+3])<<8; + $spos += 4; + $this->sheets[$this->sn]['maxrow'] = $this->_rowoffset - 1; + $this->sheets[$this->sn]['maxcol'] = $this->_coloffset - 1; + //echo "Code=".base_convert($code,10,16)." $code\n"; + unset($this->rectype); + $this->multiplier = 1; // need for format with % + switch ($code) { + case SPREADSHEET_EXCEL_READER_TYPE_DIMENSION: + //echo 'Type_DIMENSION '; + if (!isset($this->numRows)) { + if (($length == 10) || ($version == SPREADSHEET_EXCEL_READER_BIFF7)){ + $this->sheets[$this->sn]['numRows'] = ord($this->data[$spos+2]) | ord($this->data[$spos+3]) << 8; + $this->sheets[$this->sn]['numCols'] = ord($this->data[$spos+6]) | ord($this->data[$spos+7]) << 8; + } else { + $this->sheets[$this->sn]['numRows'] = ord($this->data[$spos+4]) | ord($this->data[$spos+5]) << 8; + $this->sheets[$this->sn]['numCols'] = ord($this->data[$spos+10]) | ord($this->data[$spos+11]) << 8; + } + } + //echo 'numRows '.$this->numRows.' '.$this->numCols."\n"; + break; + case SPREADSHEET_EXCEL_READER_TYPE_MERGEDCELLS: + $cellRanges = ord($this->data[$spos]) | ord($this->data[$spos+1])<<8; + for ($i = 0; $i < $cellRanges; $i++) { + $fr = ord($this->data[$spos + 8*$i + 2]) | ord($this->data[$spos + 8*$i + 3])<<8; + $lr = ord($this->data[$spos + 8*$i + 4]) | ord($this->data[$spos + 8*$i + 5])<<8; + $fc = ord($this->data[$spos + 8*$i + 6]) | ord($this->data[$spos + 8*$i + 7])<<8; + $lc = ord($this->data[$spos + 8*$i + 8]) | ord($this->data[$spos + 8*$i + 9])<<8; + //$this->sheets[$this->sn]['mergedCells'][] = array($fr + 1, $fc + 1, $lr + 1, $lc + 1); + if ($lr - $fr > 0) { + $this->sheets[$this->sn]['cellsInfo'][$fr+1][$fc+1]['rowspan'] = $lr - $fr + 1; + } + if ($lc - $fc > 0) { + $this->sheets[$this->sn]['cellsInfo'][$fr+1][$fc+1]['colspan'] = $lc - $fc + 1; + } + } + //echo "Merged Cells $cellRanges $lr $fr $lc $fc\n"; + break; + case SPREADSHEET_EXCEL_READER_TYPE_RK: + case SPREADSHEET_EXCEL_READER_TYPE_RK2: + //echo 'SPREADSHEET_EXCEL_READER_TYPE_RK'."\n"; + $row = ord($this->data[$spos]) | ord($this->data[$spos+1])<<8; + $column = ord($this->data[$spos+2]) | ord($this->data[$spos+3])<<8; + $rknum = $this->_GetInt4d($this->data, $spos + 6); + $numValue = $this->_GetIEEE754($rknum); + //echo $numValue." "; + if ($this->isDate($spos)) { + list($string, $raw) = $this->createDate($numValue); + }else{ + $raw = $numValue; + if (isset($this->_columnsFormat[$column + 1])){ + $this->curformat = $this->_columnsFormat[$column + 1]; + } + $string = sprintf($this->curformat, $numValue * $this->multiplier); + //$this->addcell(RKRecord($r)); + } + $this->addcell($row, $column, $string, $raw); + //echo "Type_RK $row $column $string $raw {$this->curformat}\n"; + break; + case SPREADSHEET_EXCEL_READER_TYPE_LABELSST: + $row = ord($this->data[$spos]) | ord($this->data[$spos+1])<<8; + $column = ord($this->data[$spos+2]) | ord($this->data[$spos+3])<<8; + $xfindex = ord($this->data[$spos+4]) | ord($this->data[$spos+5])<<8; + $index = $this->_GetInt4d($this->data, $spos + 6); + //var_dump($this->sst); + $this->addcell($row, $column, $this->sst[$index]); + //echo "LabelSST $row $column $string\n"; + break; + case SPREADSHEET_EXCEL_READER_TYPE_MULRK: + $row = ord($this->data[$spos]) | ord($this->data[$spos+1])<<8; + $colFirst = ord($this->data[$spos+2]) | ord($this->data[$spos+3])<<8; + $colLast = ord($this->data[$spos + $length - 2]) | ord($this->data[$spos + $length - 1])<<8; + $columns = $colLast - $colFirst + 1; + $tmppos = $spos+4; + for ($i = 0; $i < $columns; $i++) { + $numValue = $this->_GetIEEE754($this->_GetInt4d($this->data, $tmppos + 2)); + if ($this->isDate($tmppos-4)) { + list($string, $raw) = $this->createDate($numValue); + }else{ + $raw = $numValue; + if (isset($this->_columnsFormat[$colFirst + $i + 1])){ + $this->curformat = $this->_columnsFormat[$colFirst + $i + 1]; + } + $string = sprintf($this->curformat, $numValue * $this->multiplier); + } + //$rec['rknumbers'][$i]['xfindex'] = ord($rec['data'][$pos]) | ord($rec['data'][$pos+1]) << 8; + $tmppos += 6; + $this->addcell($row, $colFirst + $i, $string, $raw); + //echo "MULRK $row ".($colFirst + $i)." $string\n"; + } + //MulRKRecord($r); + // Get the individual cell records from the multiple record + //$num = ; + + break; + case SPREADSHEET_EXCEL_READER_TYPE_NUMBER: + $row = ord($this->data[$spos]) | ord($this->data[$spos+1])<<8; + $column = ord($this->data[$spos+2]) | ord($this->data[$spos+3])<<8; + $tmp = unpack("ddouble", substr($this->data, $spos + 6, 8)); // It machine machine dependent + if ($this->isDate($spos)) { + list($string, $raw) = $this->createDate($tmp['double']); + // $this->addcell(DateRecord($r, 1)); + }else{ + //$raw = $tmp['']; + if (isset($this->_columnsFormat[$column + 1])){ + $this->curformat = $this->_columnsFormat[$column + 1]; + } + $raw = $this->createNumber($spos); + $string = sprintf($this->curformat, $raw * $this->multiplier); + + // $this->addcell(NumberRecord($r)); + } + $this->addcell($row, $column, $string, $raw); + //echo "Number $row $column $string\n"; + break; + case SPREADSHEET_EXCEL_READER_TYPE_FORMULA: + case SPREADSHEET_EXCEL_READER_TYPE_FORMULA2: + $row = ord($this->data[$spos]) | ord($this->data[$spos+1])<<8; + $column = ord($this->data[$spos+2]) | ord($this->data[$spos+3])<<8; + if ((ord($this->data[$spos+6])==0) && (ord($this->data[$spos+12])==255) && (ord($this->data[$spos+13])==255)) { + //String formula. Result follows in a STRING record + //echo "FORMULA $row $column Formula with a string
\n"; + } elseif ((ord($this->data[$spos+6])==1) && (ord($this->data[$spos+12])==255) && (ord($this->data[$spos+13])==255)) { + //Boolean formula. Result is in +2; 0=false,1=true + } elseif ((ord($this->data[$spos+6])==2) && (ord($this->data[$spos+12])==255) && (ord($this->data[$spos+13])==255)) { + //Error formula. Error code is in +2; + } elseif ((ord($this->data[$spos+6])==3) && (ord($this->data[$spos+12])==255) && (ord($this->data[$spos+13])==255)) { + //Formula result is a null string. + } else { + // result is a number, so first 14 bytes are just like a _NUMBER record + $tmp = unpack("ddouble", substr($this->data, $spos + 6, 8)); // It machine machine dependent + if ($this->isDate($spos)) { + list($string, $raw) = $this->createDate($tmp['double']); + // $this->addcell(DateRecord($r, 1)); + }else{ + //$raw = $tmp['']; + if (isset($this->_columnsFormat[$column + 1])){ + $this->curformat = $this->_columnsFormat[$column + 1]; + } + $raw = $this->createNumber($spos); + $string = sprintf($this->curformat, $raw * $this->multiplier); + + // $this->addcell(NumberRecord($r)); + } + $this->addcell($row, $column, $string, $raw); + //echo "Number $row $column $string\n"; + } + break; + case SPREADSHEET_EXCEL_READER_TYPE_BOOLERR: + $row = ord($this->data[$spos]) | ord($this->data[$spos+1])<<8; + $column = ord($this->data[$spos+2]) | ord($this->data[$spos+3])<<8; + $string = ord($this->data[$spos+6]); + $this->addcell($row, $column, $string); + //echo 'Type_BOOLERR '."\n"; + break; + case SPREADSHEET_EXCEL_READER_TYPE_ROW: + case SPREADSHEET_EXCEL_READER_TYPE_DBCELL: + case SPREADSHEET_EXCEL_READER_TYPE_MULBLANK: + break; + case SPREADSHEET_EXCEL_READER_TYPE_LABEL: + $row = ord($this->data[$spos]) | ord($this->data[$spos+1])<<8; + $column = ord($this->data[$spos+2]) | ord($this->data[$spos+3])<<8; + $this->addcell($row, $column, substr($this->data, $spos + 8, ord($this->data[$spos + 6]) | ord($this->data[$spos + 7])<<8)); + + // $this->addcell(LabelRecord($r)); + break; + + case SPREADSHEET_EXCEL_READER_TYPE_EOF: + $cont = false; + break; + default: + //echo ' unknown :'.base_convert($r['code'],10,16)."\n"; + break; + + } + $spos += $length; + } + + if (!isset($this->sheets[$this->sn]['numRows'])) + $this->sheets[$this->sn]['numRows'] = $this->sheets[$this->sn]['maxrow']; + if (!isset($this->sheets[$this->sn]['numCols'])) + $this->sheets[$this->sn]['numCols'] = $this->sheets[$this->sn]['maxcol']; + + } + + /** + * Check whether the current record read is a date + * + * @param todo + * @return boolean True if date, false otherwise + */ + function isDate($spos) + { + //$xfindex = GetInt2d(, 4); + $xfindex = ord($this->data[$spos+4]) | ord($this->data[$spos+5]) << 8; + //echo 'check is date '.$xfindex.' '.$this->formatRecords['xfrecords'][$xfindex]['type']."\n"; + //var_dump($this->formatRecords['xfrecords'][$xfindex]); + if ($this->formatRecords['xfrecords'][$xfindex]['type'] == 'date') { + $this->curformat = $this->formatRecords['xfrecords'][$xfindex]['format']; + $this->rectype = 'date'; + return true; + } else { + if ($this->formatRecords['xfrecords'][$xfindex]['type'] == 'number') { + $this->curformat = $this->formatRecords['xfrecords'][$xfindex]['format']; + $this->rectype = 'number'; + if (($xfindex == 0x9) || ($xfindex == 0xa)){ + $this->multiplier = 100; + } + }else{ + $this->curformat = $this->_defaultFormat; + $this->rectype = 'unknown'; + } + return false; + } + } + + //}}} + //{{{ createDate() + + /** + * Convert the raw Excel date into a human readable format + * + * Dates in Excel are stored as number of seconds from an epoch. On + * Windows, the epoch is 30/12/1899 and on Mac it's 01/01/1904 + * + * @access private + * @param integer The raw Excel value to convert + * @return array First element is the converted date, the second element is number a unix timestamp + */ + function createDate($numValue) + { + if ($numValue > 1) { + $utcDays = $numValue - ($this->nineteenFour ? SPREADSHEET_EXCEL_READER_UTCOFFSETDAYS1904 : SPREADSHEET_EXCEL_READER_UTCOFFSETDAYS); + $utcValue = round(($utcDays+1) * SPREADSHEET_EXCEL_READER_MSINADAY); + $string = date ($this->curformat, $utcValue); + $raw = $utcValue; + } else { + $raw = $numValue; + $hours = floor($numValue * 24); + $mins = floor($numValue * 24 * 60) - $hours * 60; + $secs = floor($numValue * SPREADSHEET_EXCEL_READER_MSINADAY) - $hours * 60 * 60 - $mins * 60; + $string = date ($this->curformat, mktime($hours, $mins, $secs)); + } + + return array($string, $raw); + } + + function createNumber($spos) + { + $rknumhigh = $this->_GetInt4d($this->data, $spos + 10); + $rknumlow = $this->_GetInt4d($this->data, $spos + 6); + //for ($i=0; $i<8; $i++) { echo ord($this->data[$i+$spos+6]) . " "; } echo "
"; + $sign = ($rknumhigh & 0x80000000) >> 31; + $exp = ($rknumhigh & 0x7ff00000) >> 20; + $mantissa = (0x100000 | ($rknumhigh & 0x000fffff)); + $mantissalow1 = ($rknumlow & 0x80000000) >> 31; + $mantissalow2 = ($rknumlow & 0x7fffffff); + $value = $mantissa / pow( 2 , (20- ($exp - 1023))); + if ($mantissalow1 != 0) $value += 1 / pow (2 , (21 - ($exp - 1023))); + $value += $mantissalow2 / pow (2 , (52 - ($exp - 1023))); + //echo "Sign = $sign, Exp = $exp, mantissahighx = $mantissa, mantissalow1 = $mantissalow1, mantissalow2 = $mantissalow2
\n"; + if ($sign) {$value = -1 * $value;} + return $value; + } + + function addcell($row, $col, $string, $raw = '') + { + //echo "ADD cel $row-$col $string\n"; + $this->sheets[$this->sn]['maxrow'] = max($this->sheets[$this->sn]['maxrow'], $row + $this->_rowoffset); + $this->sheets[$this->sn]['maxcol'] = max($this->sheets[$this->sn]['maxcol'], $col + $this->_coloffset); + $this->sheets[$this->sn]['cells'][$row + $this->_rowoffset][$col + $this->_coloffset] = $string; + if ($raw) + $this->sheets[$this->sn]['cellsInfo'][$row + $this->_rowoffset][$col + $this->_coloffset]['raw'] = $raw; + if (isset($this->rectype)) + $this->sheets[$this->sn]['cellsInfo'][$row + $this->_rowoffset][$col + $this->_coloffset]['type'] = $this->rectype; + + } + + + function _GetIEEE754($rknum) + { + if (($rknum & 0x02) != 0) { + $value = $rknum >> 2; + } else { +//mmp +// first comment out the previously existing 7 lines of code here +// $tmp = unpack("d", pack("VV", 0, ($rknum & 0xfffffffc))); +// //$value = $tmp['']; +// if (array_key_exists(1, $tmp)) { +// $value = $tmp[1]; +// } else { +// $value = $tmp['']; +// } +// I got my info on IEEE754 encoding from +// http://research.microsoft.com/~hollasch/cgindex/coding/ieeefloat.html +// The RK format calls for using only the most significant 30 bits of the +// 64 bit floating point value. The other 34 bits are assumed to be 0 +// So, we use the upper 30 bits of $rknum as follows... + $sign = ($rknum & 0x80000000) >> 31; + $exp = ($rknum & 0x7ff00000) >> 20; + $mantissa = (0x100000 | ($rknum & 0x000ffffc)); + $value = $mantissa / pow( 2 , (20- ($exp - 1023))); + if ($sign) {$value = -1 * $value;} +//end of changes by mmp + + } + + if (($rknum & 0x01) != 0) { + $value /= 100; + } + return $value; + } + + function _encodeUTF16($string) + { + $result = $string; + if ($this->_defaultEncoding){ + switch ($this->_encoderFunction){ + case 'iconv' : $result = iconv('UTF-16LE', $this->_defaultEncoding, $string); + break; + case 'mb_convert_encoding' : $result = mb_convert_encoding($string, $this->_defaultEncoding, 'UTF-16LE' ); + break; + } + } + return $result; + } + + function _GetInt4d($data, $pos) + { + $value = ord($data[$pos]) | (ord($data[$pos+1]) << 8) | (ord($data[$pos+2]) << 16) | (ord($data[$pos+3]) << 24); + if ($value>=4294967294) + { + $value=-2; + } + return $value; + } + +} + +/* + * Local variables: + * tab-width: 4 + * c-basic-offset: 4 + * c-hanging-comment-ender-p: nil + * End: + */ + +?> From 535cb5b0599f115727fa099985fd5f30ce647665 Mon Sep 17 00:00:00 2001 From: ywarnier Date: Sun, 27 Feb 2011 03:53:38 -0500 Subject: [PATCH 2/3] Minor - Removed unnecessary logging --- main/exercice/question.class.php | 2 -- 1 file changed, 2 deletions(-) diff --git a/main/exercice/question.class.php b/main/exercice/question.class.php index 9d17f6aed2..020988ee78 100755 --- a/main/exercice/question.class.php +++ b/main/exercice/question.class.php @@ -1295,7 +1295,6 @@ abstract class Question ." (question,ponderation,position,type,level) " ." VALUES('".Database::escape_string($question_name)."'," ." $max_score , $max_position, $type, $level)"; - error_log($sql); $rs = Database::query($sql); // Get the question ID $question_id = Database::get_last_insert_id(); @@ -1309,7 +1308,6 @@ abstract class Question $sql = "INSERT INTO $tbl_quiz_rel_question " ."(question_id,exercice_id,question_order)" ." VALUES($question_id, $quiz_id, $max_order)"; - error_log($sql); $rs = Database::query($sql); return $question_id; } From 46206f430813f7f901569fe62e48508152c96b98 Mon Sep 17 00:00:00 2001 From: Yannick Warnier Date: Sun, 27 Feb 2011 03:58:00 -0500 Subject: [PATCH 3/3] Final changes to Excel import --- main/exercice/unique_answer.class.php | 26 ++++++++++++++++++++++++++ main/img/icons/32/export_excel.png | Bin 2005 -> 1982 bytes 2 files changed, 26 insertions(+) diff --git a/main/exercice/unique_answer.class.php b/main/exercice/unique_answer.class.php index dbe672607d..b72b5c9488 100755 --- a/main/exercice/unique_answer.class.php +++ b/main/exercice/unique_answer.class.php @@ -394,6 +394,32 @@ class UniqueAnswer extends Question { '; return $header; } + function create_answer($id, $question_id, $answer_title, $comment, $score = 0, $correct = 0) { + $tbl_quiz_answer = Database::get_course_table(TABLE_QUIZ_ANSWER); + $tbl_quiz_question = Database::get_course_table(TABLE_QUIZ_QUESTION); + $position = 1; + $question_id = filter_var($question_id,FILTER_SANITIZE_NUMBER_INT); + $score = filter_var($score,FILTER_SANITIZE_NUMBER_FLOAT); + $correct = filter_var($correct,FILTER_SANITIZE_NUMBER_INT); + // Get the max position + $sql = "SELECT max(position) as max_position FROM $tbl_quiz_answer " + ." WHERE question_id = $question_id"; + $rs_max = Database::query($sql); + $row_max = Database::fetch_object($rs_max); + $position = $row_max->max_position + 1; + // Insert a new answer + $sql = "INSERT INTO $tbl_quiz_answer " + ."(id, question_id,answer,correct,comment,ponderation,position,destination)" + ."VALUES ($id,$question_id,'".Database::escape_string($answer_title)."'," + ."$correct,'".Database::escape_string($comment)."',$score,$position, " + ." '0@@0@@0@@0')"; + $rs = Database::query($sql); + if ($correct) { + $sql = "UPDATE $tbl_quiz_question " + ." SET ponderation = (ponderation + $score) WHERE id = ".$question_id; + $rs = Database::query($sql, __FILE__, __LINE__); + } + } } endif; ?> diff --git a/main/img/icons/32/export_excel.png b/main/img/icons/32/export_excel.png index 1d7933c3a5ff08c3672196781cd7290c0aca6c33..4cc57e456dbc2fac5a6adc7dccd73e9915671aa9 100644 GIT binary patch delta 1947 zcmV;M2W0rw555nOBpd;AQb$4nuFf3k00006VoOIv0RI600RN!9r<0K}7=H(JNliru z+X5R1BLMkN<7)r_2R=zeK~z}7wU=#hTvZ*$f9Kr0Z^`avv&~!6l$5?eV+#!iBpGX! z@W@rSmfWE%ICCOxRzir#s zR^~p*5JKQM&bh(C!OwPfcJ^QPLSqcZ7`nT=H@dECj4?(jbw!w(nlb|e13lf{-7S@U zKMt}&B%94vUCGHShbWiJD5VI8!(GW_a?h?^yBaQMt-N@jD<@DP5q}PcX=-X}U$J7v z>o33ja>Hd4&|34q4y`r5?^9o2PfJTnM{8^A?kAsovi7nGT&V(;p_Ib+eE^!8nrLZh z>FVg{*!#>g&outu6%az8wZ`+jnYrfXW>&9WePerj`>P8nA!qw>QK_U{5Vma-4u@$- zHe$+#(V-Dir%#hgrGIc;muNKF)z;RwcjwNX%jWKDe;ffJ1VRY1#c@*OC&7S0%)D>R zG?dmTUr{Q#lrj$2FS`z-46f@Ei^Y&q-k8tl?*ks4mw;005)x8K5YRVzm=A{!P%KYj zOB<~XO6%!gz-WOsptT|(0`!lZVeN{wv?QC!<|dF*5(v>R z4)OIH?nWWW7PDxhiA2IkX~<1Y;`%-af!2!Za21F9kKwvy?Aid4NCW`S^DxG!1qsYn zz!-y+l961ROktR4oRZ5|?MhG!)rrC2@YOQDf z`&yy2rmS76gJBYUfnw>;d~vhlYgd1Un$U9Es*lr~{x^rlj+4`Qs-gj|@?u~l81Q|6 zM*8`R-G6KajFe#80yj&N7UX3T{aUm>ul3y?NBPmsz$ zE(aJuKsX3-;7rC))*4T{L}ZwvmtkyTjDPy-dg`JzoGXnI4ONkKCpkSeKs0a%`hwxv zmz9MH1a0FO$;bpu<{@Z7BmgJQ8utB1@vnUzN#$|sd_V4lM)(3-hBz^iqI;m5rg$@L zH5+*QXfL@^emeRMpFja;((yEm=Ai6A-i4kN^c*#mMhuiJYO2c&j-JF0Me%$=*?%(x zWssX2KgXn#=VbacOGG_e+P_IlLjz^sn<+vI5)d7Kxhq*$b6fnTuJw6>9Lr2Aa3TXk zSqQ`=1SDR>Czq{f_v>+ltYXWZ2|90Rpj=i+A(29&j6xu=EelWi6pF=5?u(ZyFg{)t zyQb-Z&G&DVv3Qh;Jd_30$EICyZhsQa2{3WNczGkwzA_2wpM2@2R*I{tm@0XTUehWi z*cdaf0@9=&d~xva?{vPm_x&?9A%}IX(2{`08c0+@q8j26uwoVppQWw)_}d?sa@)qW z6dg5VWIoL8G4m1tFq1nDg!}hwJNU+XoFAX$+7_sdOdF1eptc64av9b~-hbegpD*Rs zuItGceY93Hy<;&br7AEB2H_vJugxS|mh+33j!^7qWA%z!oI&s`ICNlyTS7fN_mlN3 zYhFsOP-gmoV%{EKk-su5%fhlO0Bb=4yWcu4fBev`JoUYmJo5ZU9L%kub>wIXFp|k3X0`44z;vAFQcAMfEa`N*dk-8 delta 1971 zcmV;k2Tb_B57iHlBn<>}LP=Bz2nYy#2xN$nKp1}?bVXQnQ*UN;cVTj608L?Ia&K*A zWNBd_Mrm?ocW-iQb09diXwrB900&G-L_t(og{7BWY!ufO$A9O zvtqH>F^|V{Uvcb{m=FTfG>3Y7dq3aW+S+}`6SdZ8t!Zy>UujvE)>>=Vb??f@$H#R~ zPftgCdwWB1-P^e=f}~QZvb))NaTA3?0oQ+Z2?PRdu~_WjzJ2>@?qsgK;aYzhfFeX7 z5TLHEu6f?Pd2j9AyZ5#bB><(=T?N0VDTQs@rLp?@dKN8O^k8#y^PAHtQ38Ls z-R`B7)4IpwArJ^q6RSlRG=qHu#4lea9*<*L7NJn6t*NQ$@Xnn(=iI!m=XL->2!s%% zawEh?E`kP)C_S(Bgu6=NIxhLVMLucrz?}QhuEw$~!r?Gd$_F!<%m(23DFIy9y#+!F z2?DwXPjj;WIJv?&9_c|TjjPneFQ9*wKxt6Q#VfpY4_sl%yd^Zm>Pe+Xky7IK`>Cz1 zjZUk;&8D>m38xar85ry1n=2m2MUu*;P+AcT29Q#d9v{PU91sGfT*?DwobEn{WfkyL zdI<)D0NA#T*4mvG;6??s)<`KCNGC{U`w0c_Ve^}RpmpAIR^8i%jmhDTBb0w+#)QCSftYiBXtJXt5lSRsq)S`+IC@caGvd_H_WA3}&*06bF# zFPdrRaI|7pIL3?L`YpeE=ZAm1{^1`v*%`s_E#v#&Snj`Wl`=65amnc@_*&at6hJ-G5>Q^_~+78 zexA<6e>pXLp0vtP7V>hB9R@8ygX1_Q>8CpEZd5=^2_BC?sfh`O1j7*6B2UWHJhNvz zL$<@_uS*VeZD&LC%Pg#3%Hpaepd?4)9UM(`(m$L;HMww8T4w}^R(e%7W0L3_M*!u4 zauRWi%(bh;qKac(N4S4%zQ>kT+gKLK^Ww2>1jQ>ncK?&~rTZ{#ld4FRtqV4jOsA*{ zRbttNNx^4)2X^o7E#I^6Lrlw$6dFSqq|F5gDexGO7+g%%?9cM|>eu+{(w)q&Si{zX zzbEW%WYyv}5~KZ`A3VL9V3w0q7pNMApvpwWaI$*U4klM`!Wy;^mlnq9lv0 zdRhPo2wz2jtb~j``5{|^8FZ+xn!|6_eit2Z@EG%X_3;--Oysdd}W-7 zpJ9E=YV`FMUj%=cF$G8uX@4&bv2)Ir=}B{~Wc6xi*)s zbz_Yxgd^}sKNm*hwD+`A7pbSIVma@g?IfMgOuYS?PoRH*IcC}l2GdY5A!9*D96HWw z@&g+31{LK6dIvA!@rSS-LBZDeq>qPdzrdK8;bP)4vqUu;o4-v%O$`OdE*(PC0*IEs zt&deztc^U>wk(5>bIAz>E+nBZ1>Ud(ufz^Iq*K-Ge=CBJWo&#bO6!Um3I!J_BvMFR z?II9(33?$PCJ}$4RoSW`TDM_VLBoc|j z%>d$tFQDiXPdxdP&n#I`ml@5PyHDS<&@;FBi}^GA+n;XB_ZVeSBb~_ulY^-nPP=Kw zwGhI{=kuzgqhn`pZ|}KD1T*X+fNxzZ5V#xDf4X<${|E37+7a3NbPE6g002ovPDHLk FV1k3!u~+~A