ad_page_contract { Export an assessment in IMS QTI format @author Natalia PĂ©rez (nperper@it.uc3m.es) @creation-date 2004-11-25 } -query { {assessment_id:integer,optional} } if {([info exists assessment_id] && $assessment_id ne "")} { # Get the assessment data as::assessment::data -assessment_id $assessment_id set download_name $assessment_data(title) # We get rid of spaces since they are annoying regsub -all { } $download_name {_} download_name set tmp_dir $download_name set ext "zip" append download_name ".${ext}" ad_returnredirect "${assessment_id}/${download_name}" ad_script_abort } # convenient way to get the values out of a list foreach {assessment_id download_name} [split [ad_conn path_info] /] {break} permission::require_permission -object_id $assessment_id -privilege admin # Get the assessment data as::assessment::data -assessment_id $assessment_id set assessment_id1 $assessment_data(assessment_rev_id) # publish the object to the file system set in_path [ad_mktmpdir] # create a temp dir to put the archive in set out_path [ad_mktmpdir] # First create our top-level document #set doc [dom createDocument questestinterop] dom createDocument questestinterop doc set root [$doc documentElement] # Build our XML document set assessment [$doc createElement assessment] $assessment setAttribute title $assessment_data(title) $assessment setAttribute ident $assessment_data(name) $root appendChild $assessment # as::export::new_element -value $assessment_data(description) -father $assessment -label qticomment -root $doc #, time_for_response as::export::new_element -value $assessment_data(time_for_response) -father $assessment -label duration -root $doc # if {$assessment_data(run_mode) ne "" || $assessment_data(anonymous_p) ne "" || $assessment_data(secure_access_p) ne "" || $assessment_data(reuse_responses_p) ne "" || $assessment_data(show_item_name_p) ne "" || $assessment_data(consent_page) ne "" || $assessment_data(return_url) ne "" || $assessment_data(start_time) ne "" || $assessment_data(end_time) ne "" || $assessment_data(number_tries) ne "" || $assessment_data(wait_between_tries) ne "" || $assessment_data(time_for_response) ne "" || $assessment_data(ip_mask) ne "" || $assessment_data(show_feedback) ne "" || $assessment_data(section_navigation) ne ""} { set qtimetadata [$doc createElement qtimetadata] $assessment appendChild $qtimetadata #run_mode as::export::element_qtimetadatafield -root $doc -father $qtimetadata -label run_mode -value $assessment_data(run_mode) #anonymous_p as::export::element_qtimetadatafield -root $doc -father $qtimetadata -label anonymous_p -value $assessment_data(anonymous_p) #secure_access_p as::export::element_qtimetadatafield -root $doc -father $qtimetadata -label secure_access_p -value $assessment_data(secure_access_p) #reuse_responses_p as::export::element_qtimetadatafield -root $doc -father $qtimetadata -label reuse_responses_p -value $assessment_data(reuse_responses_p) #show_item_name_p as::export::element_qtimetadatafield -root $doc -father $qtimetadata -label show_item_name_p -value $assessment_data(show_item_name_p) #consent_page as::export::element_qtimetadatafield -root $doc -father $qtimetadata -label consent_page -value $assessment_data(consent_page) #return_url as::export::element_qtimetadatafield -root $doc -father $qtimetadata -label return_url -value $assessment_data(return_url) #start_time as::export::element_qtimetadatafield -root $doc -father $qtimetadata -label start_time -value $assessment_data(start_time) #end_time as::export::element_qtimetadatafield -root $doc -father $qtimetadata -label end_time -value $assessment_data(end_time) #number_tries as::export::element_qtimetadatafield -root $doc -father $qtimetadata -label number_tries -value $assessment_data(number_tries) #wait_between_tries as::export::element_qtimetadatafield -root $doc -father $qtimetadata -label wait_between_tries -value $assessment_data(wait_between_tries) #ip_mask as::export::element_qtimetadatafield -root $doc -father $qtimetadata -label ip_mask -value $assessment_data(ip_mask) #show_feedback as::export::element_qtimetadatafield -root $doc -father $qtimetadata -label show_feedback -value $assessment_data(show_feedback) #section_navigation as::export::element_qtimetadatafield -root $doc -father $qtimetadata -label section_navigation -value $assessment_data(section_navigation) } # as::export::new_element -value $assessment_data(description) -father $assessment -label objectives -root $doc -material_p t # set assessmentcontrol [$doc createElement assessmentcontrol] if { $assessment_data(show_feedback) eq "none" } { $assessmentcontrol setAttribute feedbackswitch "No" } else { $assessmentcontrol setAttribute feedbackswitch "Yes" } $assessmentcontrol setAttribute solutionswitch "No" $assessment appendChild $assessmentcontrol # as::export::new_element -value $assessment_data(instructions) -father $assessment -label rubric -root $doc -material_p t db_multirow sections query_all_sections {} { #
set section [$doc createElement section] $section setAttribute title $section_title $section setAttribute ident $section_name $assessment appendChild $section # as::export::new_element -value $section_description -father $section -label qticomment -root $doc # set section_display_type "" set s_num_items "" set s_adp_chunk "" set s_branched_p "" set s_back_button_p "" set s_submit_answer_p "" set s_sort_order_type "" db_0or1row section_display_data {} # as::export::new_element -value $section_max_time_to_complete -father $section -label duration -root $doc if {$section_num_items ne "" || $section_points ne "" || $section_display_type ne "" || $s_num_items ne "" || $s_adp_chunk ne "" || $s_branched_p ne "" || $s_back_button_p ne "" || $s_submit_answer_p ne "" || $s_sort_order_type ne ""} { set qtimetadata [$doc createElement qtimetadata] $section appendChild $qtimetadata #num_items as::export::element_qtimetadatafield -root $doc -father $qtimetadata -label num_items -value $section_num_items #points as::export::element_qtimetadatafield -root $doc -father $qtimetadata -label points -value $section_points #display_type as::export::element_qtimetadatafield -root $doc -father $qtimetadata -label display_type -value $section_display_type #s_num_items as::export::element_qtimetadatafield -root $doc -father $qtimetadata -label s_num_items -value $s_num_items #adp_chunk as::export::element_qtimetadatafield -root $doc -father $qtimetadata -label adp_chunk -value $s_adp_chunk #branched_p as::export::element_qtimetadatafield -root $doc -father $qtimetadata -label branched_p -value $s_branched_p #back_button_p as::export::element_qtimetadatafield -root $doc -father $qtimetadata -label back_button_p -value $s_back_button_p #submit_answer_p as::export::element_qtimetadatafield -root $doc -father $qtimetadata -label submit_answer_p -value $s_submit_answer_p #sort_order_type as::export::element_qtimetadatafield -root $doc -father $qtimetadata -label sort_order_type -value $s_sort_order_type } # as::export::new_element -value $section_description -father $section -label objectives -root $doc -material_p t # as::export::new_element -value $section_instructions -father $section -label rubric -root $doc -material_p t # as::export::new_element -value $section_feedback_text -father $section -label sectionfeedback -root $doc -material_p t -attribute_label ident -attribute_value $section_id # set selection_ordering [$doc createElement selection_ordering] $section appendChild $selection_ordering # set selection [$doc createElement selection] $selection_ordering appendChild $selection # set selection_number [$doc createElement selection_number] $selection appendChild $selection_number set text [$doc createCDATASection "All"] $selection_number appendChild $text # set order [$doc createElement order] $order setAttribute order_type "Sequential" $selection_ordering appendChild $order db_foreach query_all_items {} { #reset variables set cb__display_id {} unset cb__display_id set rb__display_id {} unset rb__display_id set tb__display_id {} unset tb__display_id set ta__display_id {} unset ta__display_id set mc_id [as::item_rels::get_target -item_rev_id $as_item_id -type as_item_type_rel] set item_display_id [as::item_rels::get_target -item_rev_id $as_item_id -type as_item_display_rel] set items_as_item_id [db_string items_items_as_item_id "SELECT item_id FROM cr_revisions WHERE revision_id = :as_item_id"] #checkbox db_0or1row as_item_display_cbx "SELECT as_item_display_id AS cb__display_id FROM as_item_display_cb WHERE as_item_display_id=:item_display_id" #radiobutton db_0or1row as_item_display_rbx "SELECT as_item_display_id AS rb__display_id FROM as_item_display_rb WHERE as_item_display_id=:item_display_id" #textbox (fill-in-the-blank) db_0or1row as_item_display_tbx "SELECT as_item_display_id AS tb__display_id FROM as_item_display_tb WHERE as_item_display_id=:item_display_id" #textarea (short answer) db_0or1row as_item_display_tax "SELECT as_item_display_id AS ta__display_id FROM as_item_display_ta WHERE as_item_display_id=:item_display_id" # set item [$doc createElement item] if { $field_name ne "" } { set item_name $field_name } $item setAttribute ident $item_name $section appendChild $item # as::export::new_element -value $item_description -father $item -label qticomment -root $doc # as::export::new_element -value $item_max_time_to_complete -father $item -label duration -root $doc if {$item_field_code ne "" || $item_required_p ne "" || $item_points ne "" || $item_data_type ne ""} { set itemmetadata [$doc createElement itemmetadata] $item appendChild $itemmetadata set qtimetadata [$doc createElement qtimetadata] $itemmetadata appendChild $qtimetadata #field_code as::export::element_qtimetadatafield -root $doc -father $qtimetadata -label field_code -value $item_field_code #required_p as::export::element_qtimetadatafield -root $doc -father $qtimetadata -label required_p -value $item_required_p #points as::export::element_qtimetadatafield -root $doc -father $qtimetadata -label points -value $item_points #data_type as::export::element_qtimetadatafield -root $doc -father $qtimetadata -label data_type -value $item_data_type #multiple response or multiple choice items if {[info exists cb__display_id] || [info exists rb__display_id]} { #as_item_type_mc----------------- db_0or1row item_type_data {} #increasing_p as::export::element_qtimetadatafield -root $doc -father $qtimetadata -label increasing_p -value $increasing_p #allow_negative_p as::export::element_qtimetadatafield -root $doc -father $qtimetadata -label allow_negative_p -value $allow_negative_p #num_correct_answers as::export::element_qtimetadatafield -root $doc -father $qtimetadata -label num_correct_answers -value $num_correct_answers #num_answers as::export::element_qtimetadatafield -root $doc -father $qtimetadata -label num_answers -value $num_answers #as_item_display_rb if {[info exists rb__display_id]} { db_0or1row item_display_rb_data { } } else { db_0or1row item_display_cb_data { } } #html_display_options as::export::element_qtimetadatafield -root $doc -father $qtimetadata -label html_display_options -value $html_display_options #choice_orientation as::export::element_qtimetadatafield -root $doc -father $qtimetadata -label choice_orientation -value $choice_orientation #choice_label_orientation as::export::element_qtimetadatafield -root $doc -father $qtimetadata -label choice_label_orientation -value $choice_label_orientation #sort_order_type as::export::element_qtimetadatafield -root $doc -father $qtimetadata -label sort_order_type -value $sort_order_type #item_answer_alignment as::export::element_qtimetadatafield -root $doc -father $qtimetadata -label item_answer_alignment -value $item_answer_alignment } elseif {[info exists ta__display_id]} { db_0or1row item_display_ta_data {} #abs_size as::export::element_qtimetadatafield -root $doc -father $qtimetadata -label abs_size -value $abs_size #item_answer_alignment as::export::element_qtimetadatafield -root $doc -father $qtimetadata -label item_answer_alignment -value $item_answer_alignment } elseif {[info exists tb__display_id]} { db_0or1row item_display_tb_data {} #abs_size as::export::element_qtimetadatafield -root $doc -father $qtimetadata -label tb_abs_size -value $tb_abs_size #item_answer_alignment as::export::element_qtimetadatafield -root $doc -father $qtimetadata -label item_answer_alignment -value $item_answer_alignment } # open question item db_0or1row as_item_oq { } if {[info exists id__as_item_type_oq]} { #default_value as::export::element_qtimetadatafield -root $doc -father $qtimetadata -label default_value -value $default_value #feedback_text as::export::element_qtimetadatafield -root $doc -father $qtimetadata -label feedback_text -value $feedback_text } } # as::export::new_element -value $item_description -father $item -label objectives -root $doc -material_p t # as::export::new_element -value $item_subtext -father $item -label rubric -root $doc -material_p t # set presentation [$doc createElement presentation] $item appendChild $presentation if {![info exists tb__display_id]} { # set material [$doc createElement material] $presentation appendChild $material # set mattext [$doc createElement mattext] $mattext setAttribute texttype text/html $material appendChild $mattext set text [$doc createCDATASection $item_title] $mattext appendChild $text #content_type: imagen set content_type "" db_0or1row get_content_type_items {} if {$content_type eq "image"} { # set matimage [$doc createElement matimage] $material appendChild $matimage $matimage setAttribute uri $content_filename if {$mime_type ne ""} { $matimage setAttribute imagtype $mime_type } set cr_path [cr_fs_path $storage_area_key] file copy -force -- "${cr_path}${cr_file_name}" [file join ${in_path} $content_filename] } } #find out the item type (multiple choice or multiple response) if {[info exists cb__display_id] || [info exists rb__display_id]} { if {[info exists cb__display_id]} { # checkbox set rcardinality "Multiple" } else { # radiobutton set rcardinality "Single" } # set response_lid [$doc createElement response_lid] $response_lid setAttribute ident $item_name $response_lid setAttribute rcardinality $rcardinality $response_lid setAttribute rtiming "No" $presentation appendChild $response_lid # set render_choice [$doc createElement render_choice] $response_lid appendChild $render_choice db_foreach query_all_choices {} { # set flow_label [$doc createElement flow_label] $render_choice appendChild $flow_label # set response_label [$doc createElement response_label] $response_label setAttribute ident $choice_name $response_label setAttribute rshuffle "Yes" $flow_label appendChild $response_label # set material [$doc createElement material] $response_label appendChild $material #content_type: imagen if {$content_type eq "image"} { # set matimage [$doc createElement matimage] $material appendChild $matimage $matimage setAttribute uri $content_filename if {$mime_type ne ""} { $matimage setAttribute imagtype $mime_type } set cr_path [cr_fs_path $storage_area_key] file copy -force -- "${cr_path}${cr_file_name}" [file join ${in_path} $content_filename] } else { # set mattext [$doc createElement mattext] $mattext setAttribute texttype text/html $material appendChild $mattext set text [$doc createCDATASection $choice_title] $mattext appendChild $text } } } else { #short answer if {[info exists ta__display_id] } { # set response_str [$doc createElement response_str] $response_str setAttribute ident $item_name $response_str setAttribute rcardinality "Single" $response_str setAttribute rtiming "No" $presentation appendChild $response_str #get rows and cols for painting a textarea (in abs_size is stored as "rows value cols value", we need to add the symbol =) db_0or1row html_rows_cols "SELECT html_display_options FROM as_item_display_ta WHERE as_item_display_id=:item_display_id" if {![catch {array set html_array $html_display_options} errMsg] && [info exists html_array(rows)] && [info exists html_array(cols)]} { set rows $html_array(rows) set columns $html_array(cols) } else { set rows 15 set columns 55 } # set render_fib [$doc createElement render_fib] $render_fib setAttribute fibtype "String" $render_fib setAttribute prompt "Box" $render_fib setAttribute encoding "UTF-8" $render_fib setAttribute rows $rows $render_fib setAttribute columns $columns $response_str appendChild $render_fib # set response_label [$doc createElement response_label] $response_label setAttribute ident $item_name $response_label setAttribute rshuffle "Yes" $render_fib appendChild $response_label } else { #fill in the blank #whether it's a fill-in-blank I have to split by ns_log notice "DEBUG::1 $item_title" regsub -all -line -nocase -- "" $html ":" html1 ns_log notice "DEBUG::3 $html1" set item_title1 [split $html1 :] set longitud [llength $item_title1] for {set i 0} {$i<=[llength $item_title1]-1} {incr i 2} { ns_log notice "DEBUG::4 $i" set item_title [lindex $item_title1 $i] # set material [$doc createElement material] $presentation appendChild $material # set mattext [$doc createElement mattext] $mattext setAttribute texttype text/html $material appendChild $mattext set text [$doc createCDATASection $item_title] $mattext appendChild $text # set response_str [$doc createElement response_str] $response_str setAttribute ident $item_name$i $response_str setAttribute rcardinality "Single" $response_str setAttribute rtiming "No" $presentation appendChild $response_str # set render_fib [$doc createElement render_fib] $render_fib setAttribute fibtype "String" $render_fib setAttribute prompt "Box" $render_fib setAttribute encoding "UTF-8" $response_str appendChild $render_fib # set response_label [$doc createElement response_label] $response_label setAttribute ident $item_name $response_label setAttribute rshuffle "Yes" $render_fib appendChild $response_label } } } if { $assessment_data(survey_p) != "t" && ![info exists ta__display_id] } { # set resprocessing [$doc createElement resprocessing] $item appendChild $resprocessing # set outcomes [$doc createElement outcomes] $resprocessing appendChild $outcomes #decvar set decvar [$doc createElement decvar] $outcomes appendChild $decvar $decvar setAttribute vartype "Integer" # set respcondition [$doc createElement respcondition] $resprocessing appendChild $respcondition # set conditionvar [$doc createElement conditionvar] $respcondition appendChild $conditionvar #fill-in-blank if {[info exists tb__display_id]} { set i 0 db_foreach query_all_choices {} { # set or [$doc createElement or] $conditionvar appendChild $or set list_choice_title [list $choice_title] for {set j 0} {$j < [llength $list_choice_title]} {incr j 1} { # set varequal [$doc createElement varequal] $varequal setAttribute respident $item_name$i $or appendChild $varequal set text [$doc createCDATASection [lindex $list_choice_title $j]] $varequal appendChild $text } incr i 2 } } else { # set and [$doc createElement and] $conditionvar appendChild $and set exist_false 0 db_foreach query_all_choices2 {} { if {$correct_answer_p == "t" } { # set varequal [$doc createElement varequal] $varequal setAttribute respident $item_name $and appendChild $varequal set text [$doc createCDATASection $name] $varequal appendChild $text } else { set exist_false 1 } } if { $exist_false == 1 } { # set not [$doc createElement not] $and appendChild $not # set or [$doc createElement or] $not appendChild $or db_foreach query_all_choices2 {} { if {$correct_answer_p == "f" } { # set varequal [$doc createElement varequal] $varequal setAttribute respident $item_name $or appendChild $varequal set text [$doc createCDATASection $name] $varequal appendChild $text } } } } set num_answers_correct "" db_0or1row num_answers_correct {} if {$item_points == 1 && $num_answers_correct>1} { # set setvar [$doc createElement setvar] $setvar setAttribute varname "SCORE" $setvar setAttribute action "Add" $respcondition appendChild $setvar set text [$doc createCDATASection $item_points] $setvar appendChild $text } # set displayfeedback [$doc createElement displayfeedback] set linkrefid { } append linkrefid $item_name displayRight $displayfeedback setAttribute linkrefid $linkrefid $respcondition appendChild $displayfeedback # set respcondition [$doc createElement respcondition] $resprocessing appendChild $respcondition # set conditionvar [$doc createElement conditionvar] $respcondition appendChild $conditionvar #fill-in-blank if {[info exists tb__display_id]} { set i 0 # set not [$doc createElement not] $conditionvar appendChild $not # set and [$doc createElement and] $not appendChild $and db_foreach query_all_choices {} { # set or [$doc createElement or] $and appendChild $or set list_choice_title [list $choice_title] for {set j 0} {$j < [llength $list_choice_title]} {incr j 1} { # set varequal [$doc createElement varequal] $varequal setAttribute respident $item_name$i $or appendChild $varequal set text [$doc createCDATASection [lindex $list_choice_title $j]] $varequal appendChild $text } incr i 2 } } else { # set or [$doc createElement or] $conditionvar appendChild $or set exist_true 0 db_foreach query_all_choices2 {} { if {$correct_answer_p == "f" } { # set varequal [$doc createElement varequal] $varequal setAttribute respident $item_name $or appendChild $varequal set text [$doc createCDATASection $name] $varequal appendChild $text } else { set exist_true 1 } } if { $exist_true == 1 } { # set not [$doc createElement not] $or appendChild $not # set and [$doc createElement and] $not appendChild $and db_foreach query_all_choices2 {} { if {$correct_answer_p == "t" } { # set varequal [$doc createElement varequal] $varequal setAttribute respident $item_name $and appendChild $varequal set text [$doc createCDATASection $name] $varequal appendChild $text } } } } # set displayfeedback [$doc createElement displayfeedback] set linkrefid { } append linkrefid $item_name displayWrong $displayfeedback setAttribute linkrefid $linkrefid $respcondition appendChild $displayfeedback if {$item_points>1 || $num_answers_correct==1} { db_foreach query_all_choices {} { set i 0 # [info exists tb__display_id] because for fib item choice_correct_answer_p is null if { $choice_correct_answer_p == "t" || [info exists tb__display_id] } { set list_choice_title [list $choice_title] set length_list_choice_title [llength $list_choice_title] if {![info exists tb__display_id]} { set length_list_choice_title 1 } for {set j 0} {$j < $length_list_choice_title} {incr j 1} { # set respcondition [$doc createElement respcondition] $respcondition setAttribute title "adjustscore" $resprocessing appendChild $respcondition # set conditionvar [$doc createElement conditionvar] $respcondition appendChild $conditionvar # set varequal [$doc createElement varequal] if {[info exists tb__display_id]} { $varequal setAttribute respident $item_name$i } else { $varequal setAttribute respident $item_name } $conditionvar appendChild $varequal if {[info exists tb__display_id]} { set text [$doc createCDATASection [lindex $list_choice_title $j]] } else { set text [$doc createCDATASection $choice_name] } $varequal appendChild $text # set setvar [$doc createElement setvar] $setvar setAttribute varname "SCORE" $setvar setAttribute action "Add" $respcondition appendChild $setvar # in fib items choice_percent_score column is null if {$choice_percent_score eq ""} { set choice_percent_score 1 } else { set choice_percent_score [expr {round (($num_answers_correct * $choice_percent_score * 1.0) / 100)}] } set text [$doc createCDATASection $choice_percent_score] $setvar appendChild $text #feedback choice if {$choice_feedback_text ne ""} { set displayfeedback [$doc createElement displayfeedback] set linkrefid { } append linkrefid $choice_name feedbackChoice $displayfeedback setAttribute linkrefid $linkrefid $respcondition appendChild $displayfeedback } } } incr i 2 #for feedback choice if { $choice_correct_answer_p == "f" && $choice_feedback_text ne "" } { # set respcondition [$doc createElement respcondition] $resprocessing appendChild $respcondition # set conditionvar [$doc createElement conditionvar] $respcondition appendChild $conditionvar # set varequal [$doc createElement varequal] $varequal setAttribute respident $item_name $conditionvar appendChild $varequal set text [$doc createCDATASection $choice_name] $varequal appendChild $text #feedback choice set displayfeedback [$doc createElement displayfeedback] set linkrefid { } append linkrefid $choice_name feedbackChoice $displayfeedback setAttribute linkrefid $linkrefid $respcondition appendChild $displayfeedback } } } #feedback_wrong if {$item_feedback_wrong ne "" } { # set itemfeedback [$doc createElement itemfeedback] set ident { } append ident $item_name displayWrong $itemfeedback setAttribute ident $ident $item appendChild $itemfeedback # as::export::new_element -value $item_feedback_wrong -father $itemfeedback -label flow_mat -root $doc -material_p t } #feedback_right if {$item_feedback_right ne ""} { # set itemfeedback [$doc createElement itemfeedback] set ident { } append ident $item_name displayRight $itemfeedback setAttribute ident $ident $item appendChild $itemfeedback # as::export::new_element -value $item_feedback_right -father $itemfeedback -label flow_mat -root $doc -material_p t } #feedback_choice db_foreach query_all_choices {} { if {$choice_feedback_text ne ""} { # set itemfeedback [$doc createElement itemfeedback] set ident { } append ident $choice_name feedbackChoice $itemfeedback setAttribute ident $ident $item appendChild $itemfeedback # as::export::new_element -value $choice_feedback_text -father $itemfeedback -label flow_mat -root $doc -material_p t } } } } } #puts [$root asXML] set outfd "" append outfd "" append outfd [$root asXML] # store the tree xml into a file set file_name "$in_path/$assessment_data(title).xml" set file [open $file_name w 0600] puts $file $outfd close $file set tmp_file "[ad_generate_random_string].zip" set out_file [file join ${out_path} ${tmp_file}] # get the archive command # TODO SECURITY DONT USE GLOBBING set cmd "zip -r -9 -X '$out_file' *" # create the archive # TODO SECURITY DONT USE THE SHELL exec bash -c "cd '$in_path'; $cmd; cd -" # return the archive to the connection. ns_returnfile 200 [ns_guesstype $out_file] $out_file # clean everything up file delete -force $in_path file delete -force $out_path # Local variables: # mode: tcl # tcl-indent-level: 4 # indent-tabs-mode: nil # End: