diff --git a/bin/bamc b/bin/bamc
index eb7d9f7..c4fa5e8 100755
--- a/bin/bamc
+++ b/bin/bamc
@@ -1,29 +1,31 @@
 #!/bin/bash
 
 #!/bin/bash
 
 # Set SNAME, SDIR and SPATH
 if [ -h $0 ]; then SNAME=$(readlink $0); else SNAME=$0; fi
 SDIR=$(dirname $SNAME)
 if [[ "$SDIR" =~ ^/ ]]; then SPATH=$SDIR; else SPATH=$(realpath $(pwd)/$SDIR); fi
 
 # Set DIR_LIB
 DIR_LIB=$(realpath $SPATH/../lib/bash)
 
 # Source libs
 source $DIR_LIB/colors.sh
 source $DIR_LIB/io.sh
+source $DIR_LIB/debugging.sh
 source $DIR_LIB/cmdline_parser.sh
 source $DIR_LIB/bamc_configuration.sh
 source $DIR_LIB/bamc_help.sh
 source $DIR_LIB/bamc_workspace.sh
+source $DIR_LIB/bamc_exams.sh
 
 DEFAULT_ITEMS=""
 DEFAULT_ACTIONS="help"
 CALLBACK_PREFIX="action_"
 
 run $@
 RC=$?
 debug "Return code: $RC"
 
 exit $RC
diff --git a/lib/bash/bamc_actions.sh b/lib/bash/bamc_actions.sh
index 168278b..e595031 100644
--- a/lib/bash/bamc_actions.sh
+++ b/lib/bash/bamc_actions.sh
@@ -1,59 +1,56 @@
 #!/bin/bash
 
 function tell_if_verbose() {
     if [ "$(get_param_value 'mode')" = 'verbose' ]; then echo "$@"; fi
 }
 
-function do_list() {
-}
-
 function check_project_exists() {
 }
 
 function get_teachers() {
 }
 
 function do_test() {
 }
 
 function check_file_exists() {
 }
 
 function get_lang() {
 }
 
 function import_student_file() {
 }
 
 function get_expected_page_per_exam() {
 }
 
 function customize_tex_files() {
 }
 
 function build_sections() {
 }
 
 function do_sample() {
 }
 
 function do_check() {
 }
 
 function do_blank() {
 }
 
 function do_pdf() {
 }
 
 function build_amc_project() {
 }
 
 function add_media_files() {
 }
 
 function do_project() {
 }
 
 function do_clean() {
 }
diff --git a/lib/bash/bamc_workspace.sh b/lib/bash/bamc_exams.sh
similarity index 71%
copy from lib/bash/bamc_workspace.sh
copy to lib/bash/bamc_exams.sh
index 3b6e013..42dd8cd 100644
--- a/lib/bash/bamc_workspace.sh
+++ b/lib/bash/bamc_exams.sh
@@ -1,130 +1,129 @@
 #/bin/bash
 
-function get_workspace() {
-	is_set 'workspace'
-	if [ $? -eq 1 ]; then DIR_WORKSPACE=$(get_parameter 'workspace'); fi
-	is_set 'w'
-	if [ $? -eq 1 ]; then DIR_WORKSPACE=$(get_parameter 'w'); fi
+function action_list() {
+	# Check workspace
+	assert_workspace; if [ $? -eq 1 ]; then return 1; fi
 
-	if [ -z $DIR_WORKSPACE ]; then DIR_WORKSPACE="."; fi
+	# List exams
+	verbose "List of exams"
+	for exam in $(find $DIR_WORKSPACE/$DIR_EXAMS -mindepth 1 -maxdepth 1 -type d -exec basename {} \;); do
+		echo $exam
+	done
 
-	if [[ ! "$DIR_WORKSPACE" =~ ^/ ]]; then DIR_WORKSPACE=$(echo "$(pwd)/$DIR_WORKSPACE" | sed 's?/\.$??'); fi
+	# Done
+	return 0
 }
 
-function check_workspace() {
-	if [ -r "$1/$FILE_WORKSPACE_ROOT" ]; then
+function action_add-exam() {
+	# Check workspace
+	assert_workspace; if [ $? -eq 1 ]; then return 1; fi
+
+	# Set source
+	DIR_EXAM=$DIR_SKEL/workspace/$DIR_EXAMS/skel
+
+	if [ ! -d $DIR_EXAM ]; then
+		error_echo "Directory '$DIR_EXAM' not found."
 		return 1
-	else
-		return 0
 	fi
-}
 
-function locate_nearest_workspace() {
-	local next_dir=$DIR_WORKSPACE
-	if [ -d $next_dir ]; then next_dir=$(realpath $next_dir); fi
-	for i in $(echo 1 2 3 4); do
-		check_workspace $next_dir
-		if [ $? -eq 1 ]; then
-			# Workspace found
-			echo $next_dir
-			return
-		else
-			next_dir=$next_dir/../
-			if [ -d $next_dir ]; then next_dir=$(realpath $next_dir); fi
-		fi
-	done
-	echo "~none~"
-	return
+	is_set 'exam'
+	if [ $? -eq 1 ]; then DESTINATION=$(get_parameter 'exam'); fi
+	is_set 'e'
+	if [ $? -eq 1 ]; then DESTINATION=$(get_parameter 'e'); fi
+
+	if [ -z "$DESTINATION" ]; then error_echo "No truc provided."; fi
+	exit 1
+
+	# Set destination
+	DESTINATION=$DIR_WORKSPACE/$DIR_EXAMS/$DESTINATION
+
+	if [ -d $DESTINATION ]; then
+		confirm "Do you want to write in existing exam '$(basename $DESTINATION)' ?"
+		if [ $? -eq 0 ]; then return 1; fi
+	fi
+
+	# Copy
+	color_echo_n "Creating new exam '$(basename $DESTINATION)' from '$DIR_EXAM'... "
+	cp -rp $DIR_EXAM $DESTINATION
+	check_rc_echo $?
+	return $?
 }
 
-function assert_workspace() {
+function assert_exam() {
 	get_workspace
 	check_workspace $DIR_WORKSPACE
 	if [ $? -eq 1 ]; then return 0; fi
 	DIR_WORKSPACE=$(locate_nearest_workspace)
 	if [ "$DIR_WORKSPACE" == "~none~" ]; then
 		error_echo "No valid workspace found around here..."
 		return 1
 	fi
 	return 0
 }
 
-function action_list() {
-	# Check workspace
-	assert_workspace; if [ $? -eq 1 ]; then return 1; fi
-
-	# List exams
-	for exam in $(find $DIR_WORKSPACE/$DIR_EXAMS -mindepth 1 -maxdepth 1 -type d -exec basename {} \;); do
-		echo $exam
-	done
-
-	# Done
-	return 0
-}
-
 function action_add-exam() {
 	# Check workspace
 	assert_workspace; if [ $? -eq 1 ]; then return 1; fi
 
 	# Set source
 	DIR_EXAM=$DIR_SKEL/workspace/$DIR_EXAMS/skel
 
 	if [ ! -d $DIR_EXAM ]; then
 		error_echo "Directory '$DIR_EXAM' not found."
 		return 1
 	fi
 
 	is_set 'exam'
 	if [ $? -eq 1 ]; then DESTINATION=$(get_parameter 'exam'); fi
 	is_set 'e'
 	if [ $? -eq 1 ]; then DESTINATION=$(get_parameter 'e'); fi
 
 	if [ -z "$DESTINATION" ]; then error_echo "No truc provided."; fi
 	exit 1
 
 	# Set destination
 	DESTINATION=$DIR_WORKSPACE/$DIR_EXAMS/$DESTINATION
 
 	if [ -d $DESTINATION ]; then
 		confirm "Do you want to write in existing exam '$(basename $DESTINATION)' ?"
 		if [ $? -eq 0 ]; then return 1; fi
 	fi
 
 	# Copy
 	color_echo_n "Creating new exam '$(basename $DESTINATION)' from '$DIR_EXAM'... "
 	cp -rp $DIR_EXAM $DESTINATION
 	check_rc_echo $?
 	return $?
 }
 
 
 function action_init() {
 	get_workspace
 	EXISTING_WORKSPACE=$(locate_nearest_workspace)
 	if [ "$EXISTING_WORKSPACE" != "~none~" ]; then
 		error_echo "You cannot create a workspace within a workspace!"
 		error_echo "Detected workspace location: '$EXISTING_WORKSPACE'"
 		return 1
 	fi
 
 	confirm "Do you want to initialize workspace: '${DIR_WORKSPACE}'?"
 	if [ $? -eq 0 ]; then return 1; fi
 
 	# Create directory
 	color_echo_n "Creating directory '${DIR_WORKSPACE}'... "
 	mkdir -p $DIR_WORKSPACE
 	check_rc_echo $?
 	if [ $? -ne 0 ]; then return 1; fi
 
 	color_echo_n "Adding workspace flag... "
 	touch $DIR_WORKSPACE/$FILE_WORKSPACE_ROOT
 	check_rc_echo $?
 	if [ $? -ne 0 ]; then return 1; fi
 
 	color_echo_n "Importing skeleton files... "
 	cp -rp $DIR_SKEL/workspace/* $DIR_WORKSPACE/
 	check_rc_echo $?
 	if [ $? -ne 0 ]; then return 1; fi
 
 	return 0
 }
diff --git a/lib/bash/bamc_help.sh b/lib/bash/bamc_help.sh
index bb651a0..766c659 100644
--- a/lib/bash/bamc_help.sh
+++ b/lib/bash/bamc_help.sh
@@ -1,42 +1,42 @@
 #!/bin/bash
 
 function action_help() {
 	local item=$1 # Useless...
 	echo -e "${DarkGreen}USAGE:${NoColor} "$(basename $0)" [-p|--params p1=v1,p2-v2,...] [-o|--only item1,item2,...] action1 [action2 ...]
 
 e.g.:   $(basename $0) --params workspace=~/AMC_Workspace init
 e.g.:   $(basename $0) show 
 
 Parameters:
 -----------
 ${DarkGreen}debug${NoColor}          (GENERAL)   print debugging messages
 ${DarkGreen}force${NoColor}          (GENERAL)   do not ask for user confirmation
 ${DarkGreen}workspace|w${NoColor}    (GENERAL)   name a specific workspace
 ${DarkGreen}exam|e${NoColor}         (GENERAL)   name a specific exam within the workspace
 
 Items:
 -----------
 ${DarkGreen}item1${NoColor}          (GENERAL)   items are the existing exams (as printed by the 'list' action)
 
 Actions:
 --------
 ${DarkGreen}init${NoColor}           (WORKSPACE) create a new workspace in the current directory
 
 ${DarkGreen}add-exam${NoColor}       (EXAMS)     add a new exam in the current workspace
 ${DarkGreen}list${NoColor}           (EXAMS)     print list of exams in the current workspace
 
 ${DarkGreen}clean${NoColor}          (PROJECTS)  remove project and output directories
-${DarkGreen}project${NoColor}        (PROJECTS)  (re)build the AMC project
+${DarkGreen}project${NoColor}        (PROJECTS)  (re)build the AMC project(s)
 
 ${DarkGreen}check-latex${NoColor}    (PROJECTS)  check LaTeX syntax
 ${DarkGreen}check-cvs${NoColor}      (PROJECTS)  check CSV files syntax
 ${DarkGreen}check-amc${NoColor}      (PROJECTS)  check AMC specific syntax
 ${DarkGreen}check${NoColor}          (PROJECTS)  do all checks
 
 ${DarkGreen}blank${NoColor}          (PDF)       build a blank (anonymous) exam
 ${DarkGreen}catalog${NoColor}        (PDF)       build a catalog of questions
 ${DarkGreen}sample${NoColor}         (PDF)       build a sample (4 exams) exam
 ${DarkGreen}exam${NoColor}           (PDF)       build PDF exam"
 	return 0
 }
 
diff --git a/lib/bash/bamc_workspace.sh b/lib/bash/bamc_workspace.sh
index 3b6e013..ec2ae35 100644
--- a/lib/bash/bamc_workspace.sh
+++ b/lib/bash/bamc_workspace.sh
@@ -1,130 +1,82 @@
 #/bin/bash
 
 function get_workspace() {
 	is_set 'workspace'
 	if [ $? -eq 1 ]; then DIR_WORKSPACE=$(get_parameter 'workspace'); fi
 	is_set 'w'
 	if [ $? -eq 1 ]; then DIR_WORKSPACE=$(get_parameter 'w'); fi
 
 	if [ -z $DIR_WORKSPACE ]; then DIR_WORKSPACE="."; fi
 
 	if [[ ! "$DIR_WORKSPACE" =~ ^/ ]]; then DIR_WORKSPACE=$(echo "$(pwd)/$DIR_WORKSPACE" | sed 's?/\.$??'); fi
 }
 
 function check_workspace() {
 	if [ -r "$1/$FILE_WORKSPACE_ROOT" ]; then
 		return 1
 	else
 		return 0
 	fi
 }
 
 function locate_nearest_workspace() {
 	local next_dir=$DIR_WORKSPACE
 	if [ -d $next_dir ]; then next_dir=$(realpath $next_dir); fi
 	for i in $(echo 1 2 3 4); do
 		check_workspace $next_dir
 		if [ $? -eq 1 ]; then
 			# Workspace found
 			echo $next_dir
 			return
 		else
 			next_dir=$next_dir/../
 			if [ -d $next_dir ]; then next_dir=$(realpath $next_dir); fi
 		fi
 	done
 	echo "~none~"
 	return
 }
 
 function assert_workspace() {
 	get_workspace
 	check_workspace $DIR_WORKSPACE
 	if [ $? -eq 1 ]; then return 0; fi
 	DIR_WORKSPACE=$(locate_nearest_workspace)
 	if [ "$DIR_WORKSPACE" == "~none~" ]; then
 		error_echo "No valid workspace found around here..."
 		return 1
 	fi
 	return 0
 }
 
-function action_list() {
-	# Check workspace
-	assert_workspace; if [ $? -eq 1 ]; then return 1; fi
-
-	# List exams
-	for exam in $(find $DIR_WORKSPACE/$DIR_EXAMS -mindepth 1 -maxdepth 1 -type d -exec basename {} \;); do
-		echo $exam
-	done
-
-	# Done
-	return 0
-}
-
-function action_add-exam() {
-	# Check workspace
-	assert_workspace; if [ $? -eq 1 ]; then return 1; fi
-
-	# Set source
-	DIR_EXAM=$DIR_SKEL/workspace/$DIR_EXAMS/skel
-
-	if [ ! -d $DIR_EXAM ]; then
-		error_echo "Directory '$DIR_EXAM' not found."
-		return 1
-	fi
-
-	is_set 'exam'
-	if [ $? -eq 1 ]; then DESTINATION=$(get_parameter 'exam'); fi
-	is_set 'e'
-	if [ $? -eq 1 ]; then DESTINATION=$(get_parameter 'e'); fi
-
-	if [ -z "$DESTINATION" ]; then error_echo "No truc provided."; fi
-	exit 1
-
-	# Set destination
-	DESTINATION=$DIR_WORKSPACE/$DIR_EXAMS/$DESTINATION
-
-	if [ -d $DESTINATION ]; then
-		confirm "Do you want to write in existing exam '$(basename $DESTINATION)' ?"
-		if [ $? -eq 0 ]; then return 1; fi
-	fi
-
-	# Copy
-	color_echo_n "Creating new exam '$(basename $DESTINATION)' from '$DIR_EXAM'... "
-	cp -rp $DIR_EXAM $DESTINATION
-	check_rc_echo $?
-	return $?
-}
-
 
 function action_init() {
 	get_workspace
 	EXISTING_WORKSPACE=$(locate_nearest_workspace)
 	if [ "$EXISTING_WORKSPACE" != "~none~" ]; then
 		error_echo "You cannot create a workspace within a workspace!"
 		error_echo "Detected workspace location: '$EXISTING_WORKSPACE'"
 		return 1
 	fi
 
 	confirm "Do you want to initialize workspace: '${DIR_WORKSPACE}'?"
 	if [ $? -eq 0 ]; then return 1; fi
 
 	# Create directory
 	color_echo_n "Creating directory '${DIR_WORKSPACE}'... "
 	mkdir -p $DIR_WORKSPACE
 	check_rc_echo $?
 	if [ $? -ne 0 ]; then return 1; fi
 
 	color_echo_n "Adding workspace flag... "
 	touch $DIR_WORKSPACE/$FILE_WORKSPACE_ROOT
 	check_rc_echo $?
 	if [ $? -ne 0 ]; then return 1; fi
 
 	color_echo_n "Importing skeleton files... "
 	cp -rp $DIR_SKEL/workspace/* $DIR_WORKSPACE/
 	check_rc_echo $?
 	if [ $? -ne 0 ]; then return 1; fi
 
 	return 0
 }
diff --git a/lib/bash/cmdline_parser.sh b/lib/bash/cmdline_parser.sh
index e787d80..ff79fdd 100644
--- a/lib/bash/cmdline_parser.sh
+++ b/lib/bash/cmdline_parser.sh
@@ -1,121 +1,112 @@
 #!/bin/bash
 
 # Command line parser
 # USAGE: [in the calling script]
 # 1) set the global variables: $DEFAULT_ITEMS and $DEFAULT_ACTIONS
 # 2) set the global variable: $CALLBACK_PREFIX (default: cb_ )
 # 3) implement each the callback: e.g. function cb_list() { ... } to implement the list action
 # 4) call: run $@
 
 ACTIONS=''
 PARAMS=''
 ITEMS=''
 CALLBACK_PREFIX=${CALLBACK_PREFIX:-cb_}
 
-function error() {
-	error_echo $@
-}
-
-function debug() {
-	is_set debug
-	if [ $? -eq 1 ]; then debug_echo $@; fi
-}
-
 function parse_args() {
 	while [ $# -gt 0 ]; do
 		case $1 in
 			"-o"|"--only")
 				shift
 				ITEMS=$1
 				shift
 				continue
 				;;
 			"-p"|"--params")
 				shift
 				PARAMS=$1
 				shift
 				continue
 				;;
 			*)
 				if [ -z "$ACTIONS" ]; then ACTIONS=$1; else ACTIONS="$ACTIONS $1"; fi
 				shift
 				;;
 		esac
 	done
 	
 	if [ -z "$ITEMS" ]; then ITEMS=$(get_default_items); fi
 	if [ -z "$ITEMS" ]; then ITEMS='~no~items~'; fi
 	if [ -z "$ACTIONS" ]; then ACTIONS=$(get_default_actions); fi
 	
 	debug "actions: '$ACTIONS' | items: '$ITEMS' | parameters: '$PARAMS'"
 }
 
 function get_items() {
 	echo "$ITEMS" | sed "s/,/\n/g"
 }
 
 function get_actions() {
 	echo "$ACTIONS" | sed "s/ /\n/g"
 }
 
 function get_params() {
 	echo "$PARAMS" | sed "s/,/\n/g"
 }
 
 function get_parameter() {
 	key=$1
 	# Key alone
 	line=$(echo $PARAMS | sed "s/,/\n/g" | grep "^$key$")
 	if [ -n "$line" ]; then echo "set"; return; fi
 	# Key + value
 	line=$(echo $PARAMS | sed "s/,/\n/g" | grep "^$key=" | cut -d '=' -f 2-)
 	if [ -n "$line" ]; then echo $line; return; fi
 	# unset
 	echo "unset"
 }
 
 function is_set() {
 	param=$1
 	value=$(get_parameter $param)
 	if [ "$value" != "unset" ]; then return 1; else return 0; fi
 }
 
 function run() {
 	local action
 	local item
 	local rc=0
 	parse_args $@
 	for action in $(get_actions); do
 		for item in $(get_items); do
 			debug "Running action '$action' on item '$item'"
 			action_switch $action $item
 			rc=$((rc+$?))
 		done
 
 	done
 	return $rc
 }
 
 function get_default_items() {
 	echo $DEFAULT_ITEMS
 }
 
 function get_default_actions() {
 	echo $DEFAULT_ACTIONS
 }
 
 function action_switch() {
 	local action=$1
 	local item=$2
 	local function_to_call="${CALLBACK_PREFIX}${action}"
 	local function_exists=$(type "$function_to_call" 2>&1 | grep -c "$function_to_call"' is a function');
 	if [ $function_exists -eq 1 ]; then 
 		$function_to_call $item
 		return $?
 	else
-		error "invalid action: $action (not implemented ?)"
+		error "invalid action: $action => ${CALLBACK_PREFIX}${action} (not implemented ?)"
 		return 1
 	fi
 }
 
 # EOF
diff --git a/lib/bash/debugging.sh b/lib/bash/debugging.sh
new file mode 100644
index 0000000..8c1b1e2
--- /dev/null
+++ b/lib/bash/debugging.sh
@@ -0,0 +1,17 @@
+#!/bin/bash
+
+function error() {
+	error_echo $@
+}
+
+function debug() {
+	is_set debug
+	if [ $? -eq 1 ]; then debug_echo $@; fi
+}
+
+function verbose() {
+	is_set verbose
+	if [ $? -eq 1 ]; then color_echo $@; fi
+}
+
+# EOF
diff --git a/lib/bash/io.sh b/lib/bash/io.sh
index 6556579..f455ede 100644
--- a/lib/bash/io.sh
+++ b/lib/bash/io.sh
@@ -1,70 +1,70 @@
 #!/bin/bash
 
 function color_echo() {
 	echo -e "$@"
 }
 
 function color_echo_n() {
 	echo -en "$@"
 }
 
 function debug_echo() {
 	color_echo "${White}DEBUG:${NoColor} $@"
 }
 
 function warning_echo() {
 	color_echo "${Yellow}WARING:${NoColor} $@" 1>&2
 }
 
 function error_echo() {
 	color_echo "${Red}ERROR:${NoColor} $@" 1>&2
 }
 
 function info_echo() {
 	color_echo "${Green}INFO:${NoColor} $@"
 }
 
 function OK_echo() {
 	color_echo "${Green}OK${NoColor}"
 }
 
 function KO_echo() {
 	color_echo "${Red}KO${NoColor}"
 }
 
 function check_rc_echo {
 	if [ $1 -eq 0 ]; then OK_echo; return 0; else KO_echo; return 1; fi
 }
 
 function function_exists() {
 	function_to_test=$1
 	function_exists=$(type "$function_to_test" 2>&1 | grep -c "$function_to_test"' is a function');
 	if [ $function_exists -eq 1 ]; then return 1; else return 0; fi
 }
 
 function confirm() {
 	function_exists get_parameter
 	if [ $? -eq 1 ]; then
 		forced=$(get_parameter 'force');
 		if [ "$forced" == "set" ]; then
 			return 1
 		fi
 	fi
 	color_echo "${White}Confirmation requested:${NoColor}"
 	color_echo "$@"
-	color_echo_n "Press ${Green}Y${NoColor}(es) to confirm or ${Red}CTRL-z${NoColor} to cancel. >>> "
+	color_echo_n "Press ${Green}Y${NoColor}(es) to confirm or ${Red}ENTER${NoColor} to cancel. >>> "
 	local ans
 	read ans
 	case $ans in
 		Y|y|Yes|YES|yes)
 			color_echo "${Green}Confirmed.${NoColor}"
 			return 1
 			break;;
 		*)
 			color_echo "${Red}Cancelled.${NoColor}"
 			return 0
 			break;;
 	esac
 }
 
 # EOF