Index: openacs-4/packages/lamsint/lamsint.info
===================================================================
RCS file: /usr/local/cvsroot/openacs-4/packages/lamsint/lamsint.info,v
diff -u
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ openacs-4/packages/lamsint/lamsint.info	8 Dec 2005 09:41:07 -0000	1.1
@@ -0,0 +1,26 @@
+<?xml version="1.0"?>
+<!-- Generated by the OpenACS Package Manager -->
+
+<package key="lamsint" url="http://openacs.org/repository/apm/packages/lamsint" type="apm_application">
+    <package-name>.LRN LAMS Integration</package-name>
+    <pretty-plural>.LRN LAMS Integration</pretty-plural>
+    <initial-install-p>f</initial-install-p>
+    <singleton-p>f</singleton-p>
+
+    <version name="0.1a" url="http://openacs.org/repository/download/apm/lamsint-0.1a.apm">
+        <owner url="mailto:ernieg@melcoe.mq.edu.au">Ernie Ghiglione</owner>
+        <owner url="http://www.lamsfoundation.org">LAMS Foundation</owner>
+        <summary>.LRN LAMS integration package</summary>
+        <vendor url="http://www.lamsfoundation.org">LAMS Foundation</vendor>
+
+        <requires url="lamsconf" version="0.1d"/>
+        <requires url="general-comments" version="4.6.2"/> 
+        <maturity>0</maturity>
+
+        <!-- No dependency information -->
+
+        <callbacks>
+        </callbacks>
+
+    </version>
+</package>
Index: openacs-4/packages/lamsint/lib/user-lamsint.adp
===================================================================
RCS file: /usr/local/cvsroot/openacs-4/packages/lamsint/lib/user-lamsint.adp,v
diff -u
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ openacs-4/packages/lamsint/lib/user-lamsint.adp	8 Dec 2005 09:41:07 -0000	1.1
@@ -0,0 +1,4 @@
+<!-- LORSm Portlet Starts -->
+<listtemplate name="d_seq"></listtemplate>
+<!-- LORSm Portlet Ends -->
+  
Index: openacs-4/packages/lamsint/lib/user-lamsint.tcl
===================================================================
RCS file: /usr/local/cvsroot/openacs-4/packages/lamsint/lib/user-lamsint.tcl,v
diff -u
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ openacs-4/packages/lamsint/lib/user-lamsint.tcl	8 Dec 2005 09:41:07 -0000	1.1
@@ -0,0 +1,59 @@
+# packages/lamsint/lib/user-lamsint.tcl
+
+ad_page_contract {
+    
+    LAMS Portlet display
+    
+    @author Ernie Ghiglione (ErnieG@melcoe.mq.edu.au)
+    @creation-date 2005-11-25
+    @arch-tag: 9d893919-9a02-45cd-b6ad-19e3a34ba747
+    @cvs-id $Id: user-lamsint.tcl,v 1.1 2005/12/08 09:41:07 ernieg Exp $
+} {
+    
+} -properties {
+} -validate {
+} -errors {
+}
+
+template::list::create \
+    -name d_seq \
+    -multirow d_seq \
+    -html {width 100%} \
+    -key seq_id \
+    -no_data "No available sequences" \
+    -elements {
+        seq_name {
+            label "Title"
+	    display_eval {[string_truncate -len 25 -ellipsis "..." $display_title]}
+	    link_url_eval {[export_vars -base $comm_url/lamsint/ seq_id]} 
+	    html { width 50% }
+            link_html {title "View sequence"}
+        }
+        subject {
+            label "Subject"
+            display_eval {[dotlrn_community::get_community_name $community_id]}
+            html { align center width 50% }
+            link_url_eval {[dotlrn_community::get_community_url $community_id]}
+            link_html {title "Access Course"}       
+	}
+    }
+
+set user_id [ad_conn user_id]
+
+foreach package $package_id {
+
+    db_multirow -extend {comm_url Community} -append d_seq select_d_seq {
+	select 
+	   seq_id, display_title, introduction, hide, start_time, community_id
+	from
+	   lams_sequences
+	where 
+	   package_id = :package
+	and 
+	    hide = 'f'
+	order by start_time desc
+    } {
+        set comm_url [dotlrn_community::get_community_url $community_id]
+    }
+
+}
Index: openacs-4/packages/lamsint/sql/postgresql/lamsint-create.sql
===================================================================
RCS file: /usr/local/cvsroot/openacs-4/packages/lamsint/sql/postgresql/lamsint-create.sql,v
diff -u
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ openacs-4/packages/lamsint/sql/postgresql/lamsint-create.sql	8 Dec 2005 09:41:08 -0000	1.1
@@ -0,0 +1,65 @@
+-- 
+-- packages/lamsint/sql/postgresql/lamsint-create.sql
+-- 
+-- @author Ernie Ghiglione (ErnieG@mm.st)
+-- @creation-date 2005-11-24
+-- @arch-tag: D2DEDE3A-030F-48B9-8C3D-917D30517C32
+-- @cvs-id $Id: lamsint-create.sql,v 1.1 2005/12/08 09:41:08 ernieg Exp $
+--
+--
+--  Copyright (C) 2005 LAMS Foundation
+--
+--  This package is free software; you can redistribute it and/or modify it under the
+--  terms of the GNU General Public License as published by the Free Software
+--  Foundation; either version 2 of the License, or (at your option) any later
+--  version.
+--
+--  It is distributed in the hope that it will be useful, but WITHOUT ANY
+--  WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+--  FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more
+--  details.
+--
+
+
+-- Configuration items table for LAMS/.LRN integration
+
+CREATE TABLE lams_sequences (
+  seq_id	int
+		constraint lams_sequence_seq_id_pk
+                references acs_objects (object_id)
+		primary key,
+  user_id	int
+                constraint lams_sequence_user_id_fk
+                references users (user_id),
+  package_id 	int
+		constraint lams_sequence_pack_id_fk
+		references apm_packages (package_id), 	
+  community_id	int
+		constraint lorsm_st_track_comm_id_fk
+		references dotlrn_communities_all (community_id),
+  learning_session_id int,
+  display_title varchar(250),
+  introduction  text, 
+  hide		boolean default 'f' not null, 
+  start_time	timestamptz not null default current_timestamp,
+  end_time	timestamptz
+);
+
+
+
+begin;
+select  acs_object_type__create_type (
+          'lams_sequence',          -- object_type
+          'LAMS Sequence',              -- pretty_name
+          'LAMS Sequences',             -- pretty_plural
+          'acs_object',            -- supertype
+          'lams_sequences',       -- table_name
+          'seq_id',                -- id_column
+          null,      -- name_method
+          'f',
+          null,
+          null
+        );
+end;
+
+\i lamsint-package-create.sql
\ No newline at end of file
Index: openacs-4/packages/lamsint/sql/postgresql/lamsint-package-create.sql
===================================================================
RCS file: /usr/local/cvsroot/openacs-4/packages/lamsint/sql/postgresql/lamsint-package-create.sql,v
diff -u
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ openacs-4/packages/lamsint/sql/postgresql/lamsint-package-create.sql	8 Dec 2005 09:41:08 -0000	1.1
@@ -0,0 +1,65 @@
+-- 
+-- packages/lamsint/sql/postgresql/lamsint-package-create.sql
+-- 
+-- @author Ernie Ghiglione (ErnieG@melcoe.mq.edu.au)
+-- @creation-date 2005-11-25
+-- @arch-tag: 85E55EBE-2C6A-45D0-90B5-290B3FF1737D
+-- @cvs-id $Id: lamsint-package-create.sql,v 1.1 2005/12/08 09:41:08 ernieg Exp $
+--
+
+create or replace function lams_sequence__new (
+    integer,   -- learning_session_id
+    varchar,   -- display_title
+    varchar,   -- introduction
+    boolean,   -- hide
+    timestamp with time zone, -- creation_date
+    integer,   -- creation_user
+    varchar,    -- creation_ip
+    integer,    -- package_id
+    integer    -- community_id
+)
+returns integer as '
+declare
+    p_learning_session_id   alias for $1;
+    p_display_title         alias for $2;
+    p_introduction          alias for $3;
+    p_hide                  alias for $4;
+    p_creation_date         alias for $5;
+    p_creation_user         alias for $6;
+    p_creation_ip           alias for $7;
+    p_package_id            alias for $8;
+    p_community_id          alias for $9;
+
+    v_seq_id       integer;
+begin
+        v_seq_id := acs_object__new (
+                v_seq_id,               -- object_id
+                ''lams_sequence'',       -- object_type
+                p_creation_date,        -- creation_date
+                p_creation_user,        -- creation_user
+                p_creation_ip,          -- creation_ip
+                p_package_id,           -- context_id
+                ''t''                   -- security_inherit_p
+        );
+
+        insert into lams_sequences
+        (seq_id, user_id, community_id, learning_session_id, display_title, introduction, hide, start_time, package_id)
+        values
+        (v_seq_id, p_creation_user, p_community_id, p_learning_session_id, p_display_title, p_introduction, p_hide, p_creation_date, p_package_id);
+
+        return v_seq_id;
+end;
+' language 'plpgsql';
+
+create or replace function lams_sequence__delete (
+    integer    -- seq_id
+)
+returns integer as '
+declare 
+    p_seq_id        alias for $1;
+begin
+        perform acs_object__delete(p_seq_id);
+        delete from lams_sequences where seq_id = p_seq_id;
+        return 0;
+end;
+' language 'plpgsql';
Index: openacs-4/packages/lamsint/tcl/lamsint-procs.tcl
===================================================================
RCS file: /usr/local/cvsroot/openacs-4/packages/lamsint/tcl/lamsint-procs.tcl,v
diff -u
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ openacs-4/packages/lamsint/tcl/lamsint-procs.tcl	8 Dec 2005 09:41:08 -0000	1.1
@@ -0,0 +1,130 @@
+# packages/lamsint/tcl/lamsint-procs.tcl
+
+ad_library {
+    
+    LAMS Integration Procedures
+    
+    @author Ernie Ghiglione (ErnieG@melcoe.mq.edu.au)
+    @creation-date 2005-11-24
+    @arch-tag: 14C563A7-16CC-4104-8EA5-8B7143CE0DD9
+    @cvs-id $Id: lamsint-procs.tcl,v 1.1 2005/12/08 09:41:08 ernieg Exp $
+}
+
+#
+#  Copyright (C) 2005 LAMS Foundation
+#
+#  This package is free software; you can redistribute it and/or modify it under the
+#  terms of the GNU General Public License as published by the Free Software
+#  Foundation; either version 2 of the License, or (at your option) any later
+#  version.
+#
+#  It is distributed in the hope that it will be useful, but WITHOUT ANY
+#  WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+#  FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more
+#  details.
+#
+
+namespace eval lamsint {}
+
+ad_proc -public lamsint::add {
+    {-learning_session_id:required} 
+    {-display_title:required}
+    {-introduction ""}
+    {-hide "f"}
+    {-start_date ""}
+    {-creation_user}
+    {-package_id}
+    {-community_id}
+} {
+    Adds a new LAMS Sequence to .LRN
+
+    @param learning_session_id LAMS learning session id
+    @param display_title title for the sequence to be displayed in .LRN
+    @param introduction Introduction to be displayed in .LRN
+    @param hide boolean, whether the sequence should be hiden to students or not
+    @param start_date start date to show the sequence to students
+    @param creation_user creation user
+    @param package_id package id
+    @param community_id the community where this sequence will live.
+    @author Ernie Ghiglione (ErnieG@melcoe.mq.edu.au)
+
+} {
+
+    # this should kick in *after* we get a learning_session_id from
+    # LAMS
+
+    set creation_ip [ad_conn peeraddr]
+
+    db_transaction {
+        set seq_id [db_exec_plsql new_seq {
+	    select lams_sequence__new (
+				       :learning_session_id,
+				       :display_title,
+				       :introduction,
+				       :hide,
+				       current_timestamp,
+				       :creation_user,
+				       :creation_ip,
+				       :package_id,
+				       :community_id
+					  );
+	    
+        }
+			    ]
+	
+    }
+
+    return $seq_id
+    
+
+}
+
+ad_proc -public lamsint::get_datetime {
+
+} {
+    Generates the datetime for the hash
+
+} {
+
+    set user_now_time [lc_time_system_to_conn [dt_systime]]
+    return  [lc_time_fmt $user_now_time "%B %d,%Y %r"] 
+
+}
+
+ad_proc -public lamsint::get_lams_server_url {
+
+} {
+    Gets the lams_server_url from the LAMS Configuration package
+
+} {
+
+    set lamsconf_package_id [db_string pack_id_lams_conf {select package_id from apm_packages where package_key = 'lamsconf'}]
+    return [parameter::get -parameter lams_server_url -package_id $lamsconf_package_id]
+
+
+}
+
+
+ad_proc -public lamsint::get_server_id {
+
+} {
+    Gets the lams_server_id from the LAMS Configuration package (parameter)
+
+} {
+
+    set lamsconf_package_id [db_string pack_id_lams_conf {select package_id from apm_packages where package_key = 'lamsconf'}]
+    return [parameter::get -parameter server_id -package_id $lamsconf_package_id]
+
+}
+
+ad_proc lamsint::get_server_key {
+
+} {
+    Gets the lams_server_key from the LAMS Configuration package (parameter)
+
+} {
+
+    set lamsconf_package_id [db_string pack_id_lams_conf {select package_id from apm_packages where package_key = 'lamsconf'}]
+    return [parameter::get -parameter server_key -package_id $lamsconf_package_id]
+
+}
\ No newline at end of file
Index: openacs-4/packages/lamsint/tcl/lamsint-ws-procs.tcl
===================================================================
RCS file: /usr/local/cvsroot/openacs-4/packages/lamsint/tcl/lamsint-ws-procs.tcl,v
diff -u
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ openacs-4/packages/lamsint/tcl/lamsint-ws-procs.tcl	8 Dec 2005 09:41:08 -0000	1.1
@@ -0,0 +1,66 @@
+# packages/lamsint/tcl/lamsint-ws-procs.tcl
+
+ad_library {
+    
+    LAMS Web Services Library
+    
+    @author Ernie Ghiglione (ErnieG@mm.st)
+    @creation-date 2005-11-25
+    @arch-tag: 1F7548C7-D398-4C31-9BCB-D362C4CA0601
+    @cvs-id $Id: lamsint-ws-procs.tcl,v 1.1 2005/12/08 09:41:08 ernieg Exp $
+}
+
+namespace eval lamsint::ws {}
+
+ad_proc -public lamsint::ws::generate_hash {
+    {-datetime ""} 
+    {-username ""}
+    {-method ""}
+    {-server_id ""}
+    {-server_key ""}
+} {
+    Returns the validation hash. If method is not passed, it will not
+    be included in the hash
+
+    @param datetime
+    @param username
+    @param method (author, monitor, learner)
+    @param server_id 
+    @param server_key
+    @author Ernie Ghiglione (ErnieG@melcoe.mq.edu.au)
+
+} {
+
+    if {[empty_string_p $datetime]} {
+
+	set datetime [lamsint::get_datetime]
+
+    }
+
+    if {[empty_string_p $username]} {
+	set username [ad_conn user_id]
+	
+    }
+
+    if {[empty_string_p $server_id]} {
+	set server_id [lamsint::get_server_id]
+    }
+
+    if {[empty_string_p $server_key]} {
+	set server_key [lamsint::get_server_key]
+    }
+
+    if {[empty_string_p $method]} {
+	# we don't have a method, therefore we just create the
+	# rawstring without it
+	set rawstring [string tolower [concat $datetime$username$server_id$server_key]]
+    } else {
+
+	set rawstring [string tolower [concat $datetime$username$method$server_id$server_key]]
+    }
+
+    return [string tolower [ns_sha1 $rawstring]]
+
+}
+
+
Index: openacs-4/packages/lamsint/www/index.adp
===================================================================
RCS file: /usr/local/cvsroot/openacs-4/packages/lamsint/www/index.adp,v
diff -u
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ openacs-4/packages/lamsint/www/index.adp	8 Dec 2005 09:41:08 -0000	1.1
@@ -0,0 +1,60 @@
+<master>
+  <property name="title">@title@</property>
+  <property name="context">@context@</property>
+
+
+
+<h1>@display_title@</h1>
+<P>
+<blockquote>
+<b>Learner's Introduction</b>:
+<P>
+<div style="background-color: #D6E3E6; padding-left: 12px; padding-right: 12px; padding-top: 8px; padding-bottom: 8px; font-size: 100%; border: 1px s\olid black">
+@introduction;noquote@
+</div>
+</p>
+</blockquote>  
+</p>
+
+<!-- open LAMS Learner Link --> 
+<div class="body" align="center">
+<a class="button" href="javascript:;" onClick="window.open('@lams_server_url@/LoginRequest?uid=@username@&method=learner&ts=@datetime@&sid=@server_id@&hash=@hashValue@&course_id=@course_id@&lsid=@learning_session_id@','LAMS_Learner','height=600,width=800,resizable')">Open LAMS Learner</a>  
+</div>
+<!-- end LAMS Learner -->
+
+<if @admin_p@ eq 1>
+ <P>
+ <!-- open LAMS Monitor Link --> 
+  <div class="body" align="center">
+  <a class="button" href="javascript:;" onClick="window.open('@lams_server_url@/LoginRequest?uid=@username@&method=monitor&ts=@datetime@&sid=@server_id@&hash=@hashmonitor@&course_id=@course_id@&lsid=@learning_session_id@','LAMS_Monitor','height=600,width=800,resizable')">Open LAMS Monitor</a>  
+  </div>
+ <!-- end LAMS Learner -->
+ </p>
+</if>
+
+<p>&nbsp</p>
+<hr size="1">
+<table width="100%">
+    <tr class="list-header">
+        <th class="list" valign="top" style="background-color: #e0e0e0; font-size: 90%" colspan="2">
+
+          Tell us what you think about  @display_title@ 
+
+          <div style="float: right;">
+            @general_comments_link;noquote@
+          </div>
+
+        </th>
+    </tr>
+      <tr class="list-odd">
+	<td  valign="top" style="background-color: #f0f0f0; font-size: 80%" colspan="2">
+	  <if @the_comments@ not eq "">
+
+	    <ul>
+	      @the_comments;noquote@
+	    </ul>
+	  </if>
+
+	</td>
+      </tr>                                                                                                                                       
+</table>
Index: openacs-4/packages/lamsint/www/index.tcl
===================================================================
RCS file: /usr/local/cvsroot/openacs-4/packages/lamsint/www/index.tcl,v
diff -u
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ openacs-4/packages/lamsint/www/index.tcl	8 Dec 2005 09:41:08 -0000	1.1
@@ -0,0 +1,50 @@
+# packages/lamsint/www/index.tcl
+
+ad_page_contract {
+    
+    Jumps directly to a LAMS sequence
+    
+    @author Ernie Ghiglione (ErnieG@melcoe.mq.edu.au)
+    @creation-date 2005-11-25
+    @arch-tag: 4C94F455-80CA-4542-94BA-A1A59C6A8C54
+    @cvs-id $Id: index.tcl,v 1.1 2005/12/08 09:41:08 ernieg Exp $
+} {
+    seq_id
+} -properties {
+} -validate {
+} -errors {
+}
+
+set lams_server_url [lamsint::get_lams_server_url]
+set username [ad_verify_and_get_user_id] 
+set datetime [lamsint::get_datetime]
+set server_id [lamsint::get_server_id]
+set hashValue [lamsint::ws::generate_hash -datetime $datetime -username $username -method "learner"]
+set course_id [dotlrn_community::get_community_id]
+
+
+# LAMS Sequence info
+
+db_1row seq_info {select display_title, introduction, learning_session_id, user_id from lams_sequences where seq_id = :seq_id}
+
+set introduction [ad_convert_to_html $introduction] 
+
+set title $display_title
+set context [list "View Sequence: $display_title"]
+
+
+# if the user that started the sequence is the same as the user
+# trying to access the sequence, we give him admin access
+if {[string equal $user_id $username]} {
+    set admin_p 1
+
+    set hashmonitor [lamsint::ws::generate_hash -datetime $datetime -username $username -method "monitor"]
+
+} else {
+    set admin_p 0
+}
+
+
+# General comments
+set the_comments [general_comments_get_comments -print_content_p 1 $seq_id]
+set general_comments_link [general_comments_create_link -object_name "$display_title" -link_text "Add comments to $display_title" -link_attributes {style="font:85% arial; border: solid 1px black; background-color: \#e1e1e1; text-align: center; padding: 1px; padding-left: 8px; padding-right: 8px; color: black; text-decoration: none; white-space: nowrap;"} $seq_id [ns_conn url]?[ns_conn query]]  
\ No newline at end of file
Index: openacs-4/packages/lamsint/www/admin/add-2.tcl
===================================================================
RCS file: /usr/local/cvsroot/openacs-4/packages/lamsint/www/admin/add-2.tcl,v
diff -u
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ openacs-4/packages/lamsint/www/admin/add-2.tcl	8 Dec 2005 09:41:08 -0000	1.1
@@ -0,0 +1,49 @@
+# packages/lamsint/www/add-2.tcl
+
+ad_page_contract {
+    
+    Creates a new instance of LAMS session and adds a new sequences to a course
+    
+    @author Ernie Ghiglione (ErnieG@melcoe.mq.edu.au)
+    @creation-date 2005-11-24
+    @arch-tag: EEE6CFAB-315B-436D-A6D8-C5D3C0F89689
+    @cvs-id $Id: add-2.tcl,v 1.1 2005/12/08 09:41:08 ernieg Exp $
+} {
+    name
+    sequence:integer
+    introduction:optional
+} -properties {
+} -validate {
+} -errors {
+}
+
+#ns_write "$name $sequence"
+
+set lams_server_url [lamsint::get_lams_server_url]
+set server_id [lamsint::get_server_id]
+set username [ad_conn user_id]
+set datetime [lamsint::get_datetime]
+set course_id [dotlrn_community::get_community_id]
+set hash [lamsint::ws::generate_hash -datetime $datetime -username $username -server_id $server_id]
+
+package require SOAP
+set uri "urn:lamsws"
+set proxy "$lams_server_url/services/LearningSessionService?wsdl"
+set action "$lams_server_url/services/LearningSessionService"
+
+SOAP::create lams_get_lesson \
+   -uri $uri \
+   -action $action \
+   -proxy $proxy \
+   -name "createLearningSession" \
+    -params {"serverId" "string" "datetime" "string" "hashValue" "string" "username" "string" \
+		 "ldid" "long" "courseid" "string" "title" "string" "description" "string" \
+		 "type" "string"}
+
+set lesson_id [lams_get_lesson $server_id $datetime $hash $username $sequence $course_id $name $introduction "normal"]
+
+set seq_id [lamsint::add -learning_session_id $lesson_id -display_title $name -introduction $introduction \
+		-hide "f" -creation_user $username -package_id [ad_conn package_id] -community_id $course_id]
+
+# go back to the course page
+ad_returnredirect -message "Your sequence <b>$name</b> is now available" -html [dotlrn_community::get_community_url $course_id]
\ No newline at end of file
Index: openacs-4/packages/lamsint/www/admin/add.adp
===================================================================
RCS file: /usr/local/cvsroot/openacs-4/packages/lamsint/www/admin/add.adp,v
diff -u
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ openacs-4/packages/lamsint/www/admin/add.adp	8 Dec 2005 09:41:08 -0000	1.1
@@ -0,0 +1,737 @@
+<master>
+  <property name="title">@title@</property>
+  <property name="context">@context@</property>
+
+<form name="form" method="post" action="add-2" onSubmit="disableSumbit(this);">
+<center>
+<span id="message"></span>
+<table cellpadding="5">
+<tr valign=top>
+    <td align=right><b>Select Workspace:</b></td>
+    <td>  
+	    <select id="workspace" name="workspace"></select>
+    </td>
+</tr>
+<tr>    
+	  <td align="right"><b>Select Sequence:</b></td>
+
+    <td>
+	    <select id="sequence" name="sequence"></select> Or:
+                     <input type="button" id="create" name="create" value="Create new sequence" onClick="window.open('@lams_server_url@/LoginRequest?uid=@username@&method=author&ts=@datetime@&sid=@server_id@&hash=@hashValue@&course_id=@course_id@','LAMS_Author','height=600,width=800,resizable');">
+
+	       </td>
+</tr>
+<tr>    
+	  <td align="right"><b>Name:</b></td>
+    <td>
+        <input type="text" id="name" name="name" size="30">
+
+    </td>
+</tr>
+    <td align=right><p><b>Introduction:</b></p>
+      <br />
+    </td>
+    <td>
+<textarea id="edit-introduction" name="introduction" rows="20" cols="65"></textarea>
+    </td>
+</tr>
+
+</table>
+<input type="hidden" name="learning_session_id"/>
+<input type="hidden" name="create_sequence_url" id="create_sequence_url"/>
+<input type="submit" id="cancel" name=cancel value="Cancel">
+<input type="button" id="refresh" name="refresh" value="Refresh sequence list" onClick="refreshLists();">
+<input type="submit" id="save" name="save" value="Use selected sequence" onClick="return validate();">
+<input type="hidden" name="course"        value="@course_id@" />
+
+
+<!-- These hidden variables are always the same -->
+<input type="hidden" name=mode          value="add" />
+</center>
+
+</form>
+
+<script language="JavaScript" type="text/javascript">
+<!--
+
+		function validate(){
+			if(document.getElementById("save").value.indexOf("Update")==-1){
+				workspaceObj = document.getElementById("workspace");
+				if (workspaceObj.options.length == 0){
+					alert("No workspace was returned from LAMS server! You may try refreshing sequence list.\nIf you still get the same problem, probably you have to cancel this activity.");
+					return false;
+				}
+				sequenceObj = document.getElementById("sequence");
+				if(sequenceObj.options.length == 0){
+					alert("No sequence was returned from LAMS server! You may try refreshing sequence list.\nIf you still get the same problem, probably you have to cancel this activity.");
+					return false;
+				}
+			}
+			if(trim(document.getElementById("name").value).length==0){
+				alert("You have to specify the activity name to proceed.");
+				return false;
+			}
+			return true;
+		}
+		
+		function trim(trim_value){
+      if(trim_value.length < 1){
+        return"";
+      }
+      trim_value = rTrim(trim_value);
+      trim_value = lTrim(trim_value);
+      return trim_value;
+    } //End Function
+    
+    function rTrim(trim_value){
+      var w_space = String.fromCharCode(32);
+      var v_length = trim_value.length;
+      var strTemp = "";
+      if(v_length < 0){
+      	return"";
+      }
+      var iTemp = v_length -1;
+      
+      while(iTemp > -1){
+        if(trim_value.charAt(iTemp) != w_space){
+        	strTemp = trim_value.substring(0,iTemp +1);
+        	break;
+        }
+        iTemp = iTemp-1;
+      } //End While
+      return strTemp;
+    } //End Function
+    
+    function lTrim(trim_value){
+      var w_space = String.fromCharCode(32);
+      if(v_length < 1){
+      return"";
+      }
+      var v_length = trim_value.length;
+      var strTemp = "";
+      
+      var iTemp = 0;
+      
+      while(iTemp < v_length){
+        if(trim_value.charAt(iTemp) != w_space){
+          strTemp = trim_value.substring(iTemp,v_length);
+          break;
+        }
+        iTemp = iTemp + 1;
+      } //End While
+      return strTemp;
+    } //End Function
+		
+		function disableSubmit(dform) {
+  		if (document.getElementById) {
+   			for (var sch = 0; sch < dform.length; sch++) {
+    			if (dform.elements[sch].type.toLowerCase() == "submit") dform.elements[sch].disabled = true;
+   			}
+  		}
+			return true;
+		}
+
+		function enableSubmit(dform) {
+  		if (document.getElementById) {
+   			for (var sch = 0; sch < dform.length; sch++) {
+    			if (dform.elements[sch].type.toLowerCase() == "submit") dform.elements[sch].disabled = false;
+   			}
+  		}
+			return true;
+		}
+		
+		function disableSequenceOperation(){
+			document.getElementById("create").disabled = true;
+			document.getElementById("workspace").disabled = true;
+			document.getElementById("sequence").disabled = true;
+			document.getElementById("refresh").disabled = true;
+		}
+		
+		function updateSaveButton(){
+			document.getElementById("save").value="Update this activity";
+		}
+		
+		function updateHeaderMessage(msg,plain){
+			if(plain){
+				document.getElementById("message").innerHTML = '<p>'+msg+'</p>';
+			}else{
+				document.getElementById("message").innerHTML = 
+								'<table align="center" width="57%"  class="noticebox" border="0" cellpadding="15" cellspacing="0"><tr><td bgcolor="#FFAAAA" class="noticeboxcontent"><h4   class="main">'+msg+'</h4></td></tr></table>';
+			}
+		}
+		
+		var authorWin = null;
+		function openAuthor(url){
+			//alert(url);
+			if(authorWin && authorWin.open && !authorWin.closed){
+					authorWin.document.location = url;
+					authorWin.focus();
+			}else{
+					authorWin = window.open(url);
+					authorWin.focus();
+			}
+		}
+
+
+		var req;
+	/**
+	 * This function is to initialize elements' status and refresh workspace and sequence lists
+	 */
+    function refreshLists(){
+    	updateHeaderMessage("Please wait ...",true);
+	    disableSubmit(document.forms[0]);
+        document.getElementById("create").disabled = true;
+        document.getElementById("refresh").disabled = true;
+
+        wsSelectObj = document.getElementById("workspace");
+        wsSelectObj.options.length = 0; //remove all options
+        wsSelectObj.options[0] = new Option("Loading...", "Loading...");
+        wsSelectObj.disabled = true;
+
+        seqSelectObj = document.getElementById("sequence");
+        seqSelectObj.options.length = 0; //remove all options
+        
+        //clear the DynamicOptionList
+        dol = new DynamicOptionList("workspace","sequence");
+        dol.setFormName("form");
+        
+        url = "list?courseid="+document.form.course.value;       
+		if (window.XMLHttpRequest) { // Non-IE browsers
+			req = new XMLHttpRequest();
+			req.onreadystatechange = processStateChange;
+			try {
+				req.open("GET", url, true);
+			} catch (e) {
+				alert(e);
+			}
+			req.send(null);
+		} else if (window.ActiveXObject) { // IE
+			req = new ActiveXObject("Microsoft.XMLHTTP");
+			if (req) {
+				req.onreadystatechange = processStateChange;
+				req.open("GET", url, true);
+				req.send();
+			}
+		}
+	}
+    
+	function processStateChange() {
+		if (req.readyState == 4) { // Complete
+		      var wsSelectObj = document.getElementById("workspace");
+		      wsSelectObj.options.length = 0; //clear the workspace list
+		      wsSelectObj.disabled = false;
+		      enableSubmit(document.forms[0]);
+		      document.getElementById("create").disabled = false;
+		      document.getElementById("refresh").disabled = false;
+			if (req.status == 200) { // OK response
+		        var res = req.responseText.replace(/^\s*|\s*$/g,""); //get trimed result
+		        var seqlistStr = res.split(':'); //seperate each set of {sid, workspace,sequence}
+		        var seqlist = new Array();
+		            
+		        var workspaceList = new Object();
+		            
+		        //pass the response and construct the list again
+		        for(var i=0; i<seqlistStr.length; i++){
+		            var sws =  seqlistStr[i].split(',');
+		            if(sws.length == 3){
+		            	var sid = sws[0];
+		                var workspace = sws[1];
+		                var sequence = sws[2];
+		                    
+		                if(workspaceList[workspace] == null){
+		                    //set workspace as keys in workspaceList (kind of like a map)
+		                    //therefore duplicated workspaces will be ignored
+		                    workspaceList[workspace] = 1; //insert workspace as a key
+		                        
+		                        //insert workspace into workspace list
+		                    wsSelectObj.options[wsSelectObj.length] = new Option(workspace,workspace);
+		                }
+		                    
+		                    //insert sequence dependency into DynamicOptionList
+		                dol.forValue(workspace).addOptionsTextValue(sequence,sid);
+		            }
+		        }
+		        initDynamicOptionLists(); //construct the list
+		        updateHeaderMessage("Select an existing sequence or create a new sequence.",true);
+	        }else if(req.status == 504){//gateway timeout. probabaly LAMS server is not available.
+	        		updateHeaderMessage("It seems the LAMS server is not available!<BR> Please contact your administrator.",false);
+	        }else if(req.status == 401){//AuthenticationException thrown by LAMS server.
+	        		updateHeaderMessage("This .LRN server is not authenticated by LAMS!<BR> Please contact your administrator.",false);
+	        }else if(req.status == 502){//Unknow exception thrown by LAMS server
+	        		updateHeaderMessage("An unexpected error returned from LAMS server:"+req.responseText+"! Please contact your administrator.",false);
+	        }else if(req.status == 417){//ServerNotFound exception thrown by LAMS server
+	        		updateHeaderMessage("This .LRN server has not registered in LAMS!<BR> Please contact your administrator.",false);
+	        }else if(req.status == 402){//All LAMS module settings have not not been set up 
+	        		updateHeaderMessage("All the LAMS module settings have not been set up!<BR> Please contact your administrator.",false);
+	        }else{//this error should come from .LRN server itself
+	        		updateHeaderMessage(".LRN server error: "+req.status + " " + req.statusText+"! Please contact your administrator.",false);
+	        }
+		}
+  }
+
+	var dynamicOptionListCount=0;
+	var dynamicOptionListObjects = new Array();
+	
+	// Init call to setup lists after page load. One call to this function sets up all lists.
+	function initDynamicOptionLists() {
+		// init each DynamicOptionList object
+		for (var i=0; i<dynamicOptionListObjects.length; i++) {
+			var dol = dynamicOptionListObjects[i];
+	
+			// Find the form associated with this list
+			if (dol.formName!=null) { 
+				dol.form = document.forms[dol.formName];
+			}
+			else if (dol.formIndex!=null) {
+				dol.form = document.forms[dol.formIndex];
+			}
+			else {
+				// Form wasn't set manually, so go find it!
+				// Search for the first form element name in the lists
+				var name = dol.fieldNames[0][0];
+				for (var f=0; f<document.forms.length; f++) {
+					if (typeof(document.forms[f][name])!="undefined") {
+						dol.form = document.forms[f];
+						break;
+					}
+				}
+				if (dol.form==null) {
+					alert("ERROR: Couldn't find form element "+name+" in any form on the page! Init aborted"); return;
+				}
+			}
+	
+			// Form is found, now set the onchange attributes of each dependent select box
+			for (var j=0; j<dol.fieldNames.length; j++) {
+				// For each set of field names...
+				for (var k=0; k<dol.fieldNames[j].length-1; k++) {
+					// For each field in the set...
+					var selObj = dol.form[dol.fieldNames[j][k]];
+					if (typeof(selObj)=="undefined") { alert("Select box named "+dol.fieldNames[j][k]+" could not be found in the form. Init aborted"); return; }
+					// Map the HTML options in the first select into the options we created
+					if (k==0) {
+						if (selObj.options!=null) {
+							for (l=0; l<selObj.options.length; l++) {
+								var sopt = selObj.options[l];
+								var m = dol.findMatchingOptionInArray(dol.options,sopt.text,sopt.value,false);
+								if (m!=null) {
+									var reselectForNN6 = sopt.selected;
+									var m2 = new Option(sopt.text, sopt.value, sopt.defaultSelected, sopt.selected);
+									m2.selected = sopt.selected; // For some reason I need to do this to make NN4 happy
+									m2.defaultSelected = sopt.defaultSelected;
+									m2.DOLOption = m;
+									selObj.options[l] = m2;
+									selObj.options[l].selected = reselectForNN6; // Reselect this option for NN6 to be happy. Yuck.
+								}
+							}
+						}
+					}
+					if (selObj.onchange==null) {
+						// We only modify the onChange attribute if it's empty! Otherwise do it yourself in your source!
+						selObj.onchange = new Function("dynamicOptionListObjects["+dol.index+"].change(this)");
+					}
+				}
+			}
+		}
+		// Set the preselectd options on page load 
+		resetDynamicOptionLists();
+	}
+	
+	// This function populates lists with the preselected values. 
+	// It's pulled out into a separate function so it can be hooked into a 'reset' button on a form
+	// Optionally passed a form object which should be the only form reset
+	function resetDynamicOptionLists(theform) {
+		// reset each DynamicOptionList object
+		for (var i=0; i<dynamicOptionListObjects.length; i++) {
+			var dol = dynamicOptionListObjects[i];
+			if (typeof(theform)=="undefined" || theform==null || theform==dol.form) {
+				for (var j=0; j<dol.fieldNames.length; j++) {
+					dol.change(dol.form[dol.fieldNames[j][0]],true); // Second argument says to use preselected values rather than default values
+				}
+			}
+		}
+	}
+	
+	// An object to represent an Option() but just for data-holding
+	function DOLOption(text,value,defaultSelected,selected) {
+		this.text = text;
+		this.value = value;
+		this.defaultSelected = defaultSelected;
+		this.selected = selected;
+		this.options = new Array(); // To hold sub-options
+		return this;
+	}
+	
+	// DynamicOptionList CONSTRUCTOR
+	function DynamicOptionList() {
+		this.form = null;// The form this list belongs to
+		this.options = new Array();// Holds the options of dependent lists
+		this.longestString = new Array();// Longest string that is currently a potential option (for Netscape)
+		this.numberOfOptions = new Array();// The total number of options that might be displayed, to build dummy options (for Netscape)
+		this.currentNode = null;// The current node that has been selected with forValue() or forText()
+		this.currentField = null;// The current field that is selected to be used for setValue()
+		this.currentNodeDepth = 0;// How far down the tree the currentNode is
+		this.fieldNames = new Array();// Lists of dependent fields which use this object
+		this.formIndex = null;// The index of the form to associate with this list
+		this.formName = null;// The name of the form to associate with this list
+		this.fieldListIndexes = new Object();// Hold the field lists index where fields exist
+		this.fieldIndexes = new Object();// Hold the index within the list where fields exist
+		this.selectFirstOption = true;// Whether or not to select the first option by default if no options are default or preselected, otherwise set the selectedIndex = -1
+		this.numberOfOptions = new Array();// Store the max number of options for a given option list
+		this.longestString = new Array();// Store the longest possible string 
+		this.values = new Object(); // Will hold the preselected values for fields, by field name
+		
+		// Method mappings
+		this.forValue = DOL_forValue;
+		this.forText = DOL_forText;
+		this.forField = DOL_forField;
+		this.forX = DOL_forX;
+		this.addOptions = DOL_addOptions;
+		this.addOptionsTextValue = DOL_addOptionsTextValue;
+		this.setDefaultOptions = DOL_setDefaultOptions;
+		this.setValues = DOL_setValues;
+		this.setValue = DOL_setValues;
+		this.setFormIndex = DOL_setFormIndex;
+		this.setFormName = DOL_setFormName;
+		this.printOptions = DOL_printOptions;
+		this.addDependentFields = DOL_addDependentFields;
+		this.change = DOL_change;
+		this.child = DOL_child;
+		this.selectChildOptions = DOL_selectChildOptions;
+		this.populateChild = DOL_populateChild;
+		this.change = DOL_change;
+		this.addNewOptionToList = DOL_addNewOptionToList;
+		this.findMatchingOptionInArray = DOL_findMatchingOptionInArray;
+	
+		// Optionally pass in the dependent field names
+		if (arguments.length > 0) {
+			// Process arguments and add dependency groups
+			for (var i=0; i<arguments.length; i++) {
+				this.fieldListIndexes[arguments[i].toString()] = this.fieldNames.length;
+				this.fieldIndexes[arguments[i].toString()] = i;
+			}
+			this.fieldNames[this.fieldNames.length] = arguments;
+		}
+		
+		// Add this object to the global array of dynamicoptionlist objects
+		this.index = window.dynamicOptionListCount++;
+		window["dynamicOptionListObjects"][this.index] = this;
+	}
+	
+	// Given an array of Option objects, search for an existing option that matches value, text, or both
+	function DOL_findMatchingOptionInArray(a,text,value,exactMatchRequired) {
+		if (a==null || typeof(a)=="undefined") { return null; }
+		var value_match = null; // Whether or not a value has been matched
+		var text_match = null; // Whether or not a text has been matched
+		for (var i=0; i<a.length; i++) {
+			var opt = a[i];
+			// If both value and text match, return it right away
+			if (opt.value==value && opt.text==text) { return opt; }
+			if (!exactMatchRequired) {
+				// If value matches, store it until we complete scanning the list
+				if (value_match==null && value!=null && opt.value==value) {
+					value_match = opt;
+				}
+				// If text matches, store it for later
+				if (text_match==null && text!=null && opt.text==text) {
+					text_match = opt;
+				}
+			}
+		}
+		return (value_match!=null)?value_match:text_match;
+	}
+	
+	// Util function used by forValue and forText
+	function DOL_forX(s,type) {
+		if (this.currentNode==null) { this.currentNodeDepth=0; }
+		var useNode = (this.currentNode==null)?this:this.currentNode;
+		var o = this.findMatchingOptionInArray(useNode["options"],(type=="text")?s:null,(type=="value")?s:null,false);
+		if (o==null) {
+			o = new DOLOption(null,null,false,false);
+			o[type] = s;
+			useNode.options[useNode.options.length] = o;
+		}
+		this.currentNode = o;
+		this.currentNodeDepth++;
+		return this;
+	}
+	
+	// Set the portion of the list structure that is to be used by a later operation like addOptions
+	function DOL_forValue(s) { return this.forX(s,"value"); }
+	
+	// Set the portion of the list structure that is to be used by a later operation like addOptions
+	function DOL_forText(s) { return this.forX(s,"text"); }
+	
+	// Set the field to be used for setValue() calls
+	function DOL_forField(f) { this.currentField = f; return this; }
+	
+	// Create and add an option to a list, avoiding duplicates
+	function DOL_addNewOptionToList(a, text, value, defaultSelected) {
+		var o = new DOLOption(text,value,defaultSelected,false);
+		// Add the option to the array
+		if (a==null) { a = new Array(); }
+		for (var i=0; i<a.length; i++) {
+			if (a[i].text==o.text && a[i].value==o.value) {
+				if (o.selected) { 
+					a[i].selected=true;
+				}
+				if (o.defaultSelected) {
+					a[i].defaultSelected = true;
+				}
+				return a;
+			}
+		}
+		a[a.length] = o;
+	}
+	
+	// Add sub-options to the currently-selected node, with the same text and value for each option
+	function DOL_addOptions() {
+		if (this.currentNode==null) { this.currentNode = this; }
+		if (this.currentNode["options"] == null) { this.currentNode["options"] = new Array(); }
+		for (var i=0; i<arguments.length; i++) {
+			var text = arguments[i];
+			this.addNewOptionToList(this.currentNode.options,text,text,false);
+			if (typeof(this.numberOfOptions[this.currentNodeDepth])=="undefined") {
+				this.numberOfOptions[this.currentNodeDepth]=0;
+			}
+			if (this.currentNode.options.length > this.numberOfOptions[this.currentNodeDepth]) {
+				this.numberOfOptions[this.currentNodeDepth] = this.currentNode.options.length;
+			}
+			if (typeof(this.longestString[this.currentNodeDepth])=="undefined" || (text.length > this.longestString[this.currentNodeDepth].length)) {
+				this.longestString[this.currentNodeDepth] = text;
+			}
+		}
+		this.currentNode = null;
+		this.currentNodeDepth = 0;
+	}
+	
+	// Add sub-options to the currently-selected node, specifying separate text and values for each option
+	function DOL_addOptionsTextValue() {
+		if (this.currentNode==null) { this.currentNode = this; }
+		if (this.currentNode["options"] == null) { this.currentNode["options"] = new Array(); }
+		for (var i=0; i<arguments.length; i++) {
+			var text = arguments[i++];
+			var value = arguments[i];
+			this.addNewOptionToList(this.currentNode.options,text,value,false);
+			if (typeof(this.numberOfOptions[this.currentNodeDepth])=="undefined") {
+				this.numberOfOptions[this.currentNodeDepth]=0;
+			}
+			if (this.currentNode.options.length > this.numberOfOptions[this.currentNodeDepth]) {
+				this.numberOfOptions[this.currentNodeDepth] = this.currentNode.options.length;
+			}
+			if (typeof(this.longestString[this.currentNodeDepth])=="undefined" || (text.length > this.longestString[this.currentNodeDepth].length)) {
+				this.longestString[this.currentNodeDepth] = text;
+			}
+		}
+		this.currentNode = null;
+		this.currentNodeDepth = 0;
+	}
+	
+	// Find the first dependent list of a select box
+	// If it's the last list in a chain, return null because there are no children
+	function DOL_child(obj) {
+		var listIndex = this.fieldListIndexes[obj.name];
+		var index = this.fieldIndexes[obj.name];
+		if (index < (this.fieldNames[listIndex].length-1)) {
+			return this.form[this.fieldNames[listIndex][index+1]];
+		}
+		return null;
+	}
+	
+	// Set the options which should be selected by default for a certain value in the parent
+	function DOL_setDefaultOptions() {
+		if (this.currentNode==null) { this.currentNode = this; }
+		for (var i=0; i<arguments.length; i++) {
+			var o = this.findMatchingOptionInArray(this.currentNode.options,null,arguments[i],false);
+			if (o!=null) {
+				o.defaultSelected = true;
+			}
+		}
+		this.currentNode = null;
+	}
+	
+	// Set the options which should be selected when the page loads. This is different than the default value and ONLY applies when the page LOADS
+	function DOL_setValues() {
+		if (this.currentField==null) { 
+			alert("Can't call setValues() without using forField() first!");
+			return;
+		}
+		if (typeof(this.values[this.currentField])=="undefined") {
+			this.values[this.currentField] = new Object();
+		}
+		for (var i=0; i<arguments.length; i++) {
+			this.values[this.currentField][arguments[i]] = true;
+		}
+		this.currentField = null;
+	}
+	
+	// Manually set the form for the object using an index
+	function DOL_setFormIndex(i) {
+		this.formIndex = i;
+	}
+	
+	// Manually set the form for the object using a form name
+	function DOL_setFormName(n) {
+		this.formName = n;
+	}
+	
+	// Print blank <option> objects for Netscape4, since it refuses to grow or shrink select boxes for new options
+	function DOL_printOptions(name) {
+		// Only need to write out "dummy" options for Netscape4
+	    if ((navigator.appName == 'Netscape') && (parseInt(navigator.appVersion) <= 4)){
+			var index = this.fieldIndexes[name];
+			var ret = "";
+			if (typeof(this.numberOfOptions[index])!="undefined") {
+				for (var i=0; i<this.numberOfOptions[index]; i++) { 
+					ret += "<OPTION>";
+				}
+			}
+			ret += "<OPTION>";
+			if (typeof(this.longestString[index])!="undefined") {
+				for (var i=0; i<this.longestString[index].length; i++) {
+					ret += "_";
+				}
+			}
+			document.writeln(ret);
+		}
+	}
+	
+	// Add a list of field names which use this option-mapping object.
+	// A single mapping object may be used by multiple sets of fields
+	function DOL_addDependentFields() {
+		for (var i=0; i<arguments.length; i++) {
+			this.fieldListIndexes[arguments[i].toString()] = this.fieldNames.length;
+			this.fieldIndexes[arguments[i].toString()] = i;
+		}
+		this.fieldNames[this.fieldNames.length] = arguments;
+	}
+	
+	// Called when a parent select box is changed. It populates its direct child, then calls change on the child object to continue the population.
+	function DOL_change(obj, usePreselected) {
+		if (usePreselected==null || typeof(usePreselected)=="undefined") { usePreselected = false; }
+		var changedListIndex = this.fieldListIndexes[obj.name];
+		var changedIndex = this.fieldIndexes[obj.name];
+		var child = this.child(obj);
+		if (child == null) { return; } // No child, no need to continue
+		if (obj.type == "select-one") {
+			// Treat single-select differently so we don't have to scan the entire select list, which could potentially speed things up
+			if (child.options!=null) {
+				child.options.length=0; // Erase all the options from the child so we can re-populate
+			}
+			if (obj.options!=null && obj.options.length>0 && obj.selectedIndex>=0) {
+				var o = obj.options[obj.selectedIndex];
+				this.populateChild(o.DOLOption,child,usePreselected);
+				this.selectChildOptions(child,usePreselected);
+			}
+		}
+		else if (obj.type == "select-multiple") {
+			// For each selected value in the parent, find the options to fill in for this list
+			// Loop through the child list and keep track of options that are currently selected
+			var currentlySelectedOptions = new Array();
+			if (!usePreselected) {
+				for (var i=0; i<child.options.length; i++) {
+					var co = child.options[i];
+					if (co.selected) {
+						this.addNewOptionToList(currentlySelectedOptions, co.text, co.value, co.defaultSelected);
+					}
+				}
+			}
+			child.options.length=0;
+			if (obj.options!=null) {
+				var obj_o = obj.options;
+				// For each selected option in the parent...
+				for (var i=0; i<obj_o.length; i++) {
+					if (obj_o[i].selected) {
+						// if option is selected, add its children to the list
+	 					this.populateChild(obj_o[i].DOLOption,child,usePreselected);
+					}
+				}
+				// Now go through and re-select any options which were selected before
+				var atLeastOneSelected = false;
+				if (!usePreselected) {
+					for (var i=0; i<child.options.length; i++) {
+						var m = this.findMatchingOptionInArray(currentlySelectedOptions,child.options[i].text,child.options[i].value,true);
+						if (m!=null) {
+							child.options[i].selected = true;
+							atLeastOneSelected = true;
+						}
+					}
+				}
+				if (!atLeastOneSelected) {	
+					this.selectChildOptions(child,usePreselected);
+				}
+			}
+		}
+		// Change all the way down the chain
+		this.change(child,usePreselected);
+	}
+	function DOL_populateChild(dolOption,childSelectObj,usePreselected) {
+		// If this opton has sub-options, populate the child list with them
+		if (dolOption!=null && dolOption.options!=null) {
+			for (var j=0; j<dolOption.options.length; j++) {
+				var srcOpt = dolOption.options[j];
+				if (childSelectObj.options==null) { childSelectObj.options = new Array(); }
+				// Put option into select list
+				var duplicate = false;
+				var preSelectedExists = false;
+				for (var k=0; k<childSelectObj.options.length; k++) {
+					var csi = childSelectObj.options[k];
+					if (csi.text==srcOpt.text && csi.value==srcOpt.value) {
+						duplicate = true;
+						break;
+					}
+				}
+				if (!duplicate) {
+					var newopt = new Option(srcOpt.text, srcOpt.value, false, false);
+					newopt.selected = false; // Again, we have to do these two statements for NN4 to work
+					newopt.defaultSelected = false;
+					newopt.DOLOption = srcOpt;
+					childSelectObj.options[childSelectObj.options.length] = newopt;
+				}
+			}
+		}
+	}
+	
+	// Once a child select is populated, go back over it to select options which should be selected
+	function DOL_selectChildOptions(obj,usePreselected) {
+		// Look to see if any options are preselected=true. If so, then set then selected if usePreselected=true, otherwise set defaults
+		var values = this.values[obj.name];
+		var preselectedExists = false;
+		if (usePreselected && values!=null && typeof(values)!="undefined") {
+			for (var i=0; i<obj.options.length; i++) {
+				var v = obj.options[i].value;
+				if (v!=null && values[v]!=null && typeof(values[v])!="undefined") {
+					preselectedExists = true;
+					break;
+				}
+			}
+		}
+		// Go back over all the options to do the selection
+		var atLeastOneSelected = false;
+		for (var i=0; i<obj.options.length; i++) {
+			var o = obj.options[i];
+			if (preselectedExists && o.value!=null && values[o.value]!=null && typeof(values[o.value])!="undefined") {
+				o.selected = true;
+				atLeastOneSelected = true;
+			}
+			else if (!preselectedExists && o.DOLOption!=null && o.DOLOption.defaultSelected) {
+				o.selected = true;
+				atLeastOneSelected = true;
+			}
+			else {
+				o.selected = false;
+			}
+		}
+		// If nothing else was selected, select the first one by default
+		if (this.selectFirstOption && !atLeastOneSelected && obj.options.length>0) {
+			obj.options[0].selected = true;
+		}
+		else if (!atLeastOneSelected &&  obj.type=="select-one") {
+			obj.selectedIndex = -1;
+		}
+	}
+    
+    
+-->
+</script>
+
+<script language="JavaScript" type="text/javascript">refreshLists();</script>	  
Index: openacs-4/packages/lamsint/www/admin/add.tcl
===================================================================
RCS file: /usr/local/cvsroot/openacs-4/packages/lamsint/www/admin/add.tcl,v
diff -u
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ openacs-4/packages/lamsint/www/admin/add.tcl	8 Dec 2005 09:41:08 -0000	1.1
@@ -0,0 +1,39 @@
+# packages/lamsint/www/add.tcl
+
+ad_page_contract {
+    
+    Adds a LAMS sequence
+    
+    @author Ernie Ghiglione (ErnieG@gmail.com)
+    @creation-date 2005-10-07
+    @arch-tag: 58db8d76-7110-4ffe-9b9d-801272aa479d
+    @cvs-id $Id: add.tcl,v 1.1 2005/12/08 09:41:08 ernieg Exp $
+} {
+    
+} -properties {
+} -validate {
+} -errors {
+}
+
+set title "Add LAMS sequence"
+set context [list "Add LAMS sequence"]
+
+
+
+# get parameters data
+set datetime [lamsint::get_datetime]
+set lams_server_url [lamsint::get_lams_server_url]
+set server_id [lamsint::get_server_id]
+set username [ad_verify_and_get_user_id] 
+
+# get course data
+set course_id [dotlrn_community::get_community_id]
+
+set hashValue [lamsint::ws::generate_hash -datetime $datetime -username $username -method "author"]
+
+
+
+
+
+
+
Index: openacs-4/packages/lamsint/www/admin/hide.tcl
===================================================================
RCS file: /usr/local/cvsroot/openacs-4/packages/lamsint/www/admin/hide.tcl,v
diff -u
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ openacs-4/packages/lamsint/www/admin/hide.tcl	8 Dec 2005 09:41:08 -0000	1.1
@@ -0,0 +1,37 @@
+# packages/lamsint/www/admin/hide.tcl
+
+ad_page_contract {
+    
+    Hide or displays a sequence
+    changes the display info for a sequence and returns back to the admin page
+    @author Ernie Ghiglione (ErnieG@gmail.com)
+    @creation-date 2005-11-29
+    @arch-tag: b93459cd-311d-41ea-b5f2-ddb403fb64df
+    @cvs-id $Id: hide.tcl,v 1.1 2005/12/08 09:41:08 ernieg Exp $
+} {
+    seq_id:integer
+    hide
+} -properties {
+} -validate {
+} -errors {
+}
+
+# checks whether the user has permissions on the sequence. 
+
+permission::require_permission -object_id $seq_id -privilege admin
+
+if { [string equal $hide "f"] } {
+
+    db_dml update_seq_display {
+	update lams_sequences  set hide = 't' where seq_id = :seq_id
+    }
+    
+} else {
+
+    db_dml update_seq_display {
+	update lams_sequences  set hide = 'f' where seq_id = :seq_id
+    }
+
+
+}
+ad_returnredirect -message "Display changed successfully!" [export_vars  -base index seq_id]
\ No newline at end of file
Index: openacs-4/packages/lamsint/www/admin/index.adp
===================================================================
RCS file: /usr/local/cvsroot/openacs-4/packages/lamsint/www/admin/index.adp,v
diff -u
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ openacs-4/packages/lamsint/www/admin/index.adp	8 Dec 2005 09:41:08 -0000	1.1
@@ -0,0 +1,15 @@
+<master>
+  <property name="title">@title@</property>
+  <property name="context">@context@</property>
+
+<p>
+<a title="Add a LAMS Sequence to this course" href="add" class="button"> Add a LAMS Sequence </a>
+&nbsp;&nbsp;
+<a title="Open LAMS Authoring to create or edit sequences" href="javascript:;" onClick="window.open('@lams_server_url@/LoginRequest?uid=@username@&method=author&ts=@datetime@&sid=@server_id@&hash=@hashauthor@&course_id=@course_id@','LAMS_Author','height=600,width=800,resizable')")" class="button"> LAMS Author </a>
+&nbsp;&nbsp;
+<a title="Open LAMS Monitor to monitor your sequences" href="javascript:;" onClick="window.open('@lams_server_url@/LoginRequest?uid=@username@&method=monitor&ts=@datetime@&sid=@server_id@&hash=@hashmonitor@&course_id=@course_id@','LAMS_Monitor','height=600,width=800,resizable')")" class="button"> LAMS Monitor </a>
+
+</p>
+
+<listtemplate name="d_seq"></listtemplate>
+
Index: openacs-4/packages/lamsint/www/admin/index.tcl
===================================================================
RCS file: /usr/local/cvsroot/openacs-4/packages/lamsint/www/admin/index.tcl,v
diff -u
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ openacs-4/packages/lamsint/www/admin/index.tcl	8 Dec 2005 09:41:08 -0000	1.1
@@ -0,0 +1,86 @@
+# packages/lamsint/www/admin/index.tcl
+
+ad_page_contract {
+    
+    LAMS Integration Admin
+    
+    @author Ernie Ghiglione (ErnieG@melcoe.mq.edu.au)
+    @creation-date 2005-11-25
+    @arch-tag: 27C699D8-3D23-4EB1-9FAD-DB6A0762081F
+    @cvs-id $Id: index.tcl,v 1.1 2005/12/08 09:41:08 ernieg Exp $
+} {
+    
+} -properties {
+} -validate {
+} -errors {
+}
+
+# 
+set title "LAMS Administration"
+set context [list "LAMS Administration"]
+
+# LAMS Variables & settings 
+set username [ad_verify_and_get_user_id] 
+set package_id [ad_conn package_id]
+set lams_server_url [lamsint::get_lams_server_url]
+set datetime [lamsint::get_datetime]
+set server_id [lamsint::get_server_id]
+set course_id [dotlrn_community::get_community_id]
+
+set hashauthor [lamsint::ws::generate_hash  -datetime $datetime -username $username -method "author"]
+set hashmonitor [lamsint::ws::generate_hash  -datetime $datetime -username $username -method "monitor"]
+
+template::list::create \
+    -name d_seq \
+    -multirow d_seq \
+    -html {width 100%} \
+    -key seq_id \
+    -no_data "No available sequences" \
+    -elements {
+        seq_name {
+            label "Title"
+	    display_eval {[string_truncate -len 40 -ellipsis "..." $display_title]}
+	    link_url_eval {[export_vars -base ../index seq_id]} 
+            link_html {title "View sequence"}
+        }
+	hide {
+	    label "Display?"
+	    display_template {@d_seq.hide_p;noquote@}
+            html {align "center"} 
+
+	}
+        creation_user {
+            label "Started by"
+            display_eval {[person::name -person_id $creation_user]}
+            link_url_eval {[acs_community_member_url -user_id $creation_user]}
+            html {align "center"}   
+	}
+	start_time {
+	    label "Started"
+	    display_eval {[lc_time_fmt $start_time "%x %X"]}
+            html {align "center"}                            
+	}
+	
+    }
+
+
+db_multirow -extend {hide_p} d_seq select_d_seq {
+    select 
+    seq_id, display_title, introduction, hide, start_time, user_id as creation_user
+    from
+    lams_sequences
+    where 
+    package_id = :package_id
+    order by start_time desc
+} {
+
+    # show Display or Hide checkbox
+    if {[string equal $hide "f"]} {
+	set hide_p "<a href=\"[export_vars -base hide {seq_id hide}]\" title=\"Click to hide\"><img src=\"/resources/checkboxchecked.gif\"></a>"
+
+    } else {
+	set hide_p "<a href=\"[export_vars -base hide {seq_id hide}]\" title=\"Click to display\"><img src=\"/resources/checkbox.gif\"></a>"
+    }
+
+}
+
Index: openacs-4/packages/lamsint/www/admin/list.tcl
===================================================================
RCS file: /usr/local/cvsroot/openacs-4/packages/lamsint/www/admin/list.tcl,v
diff -u
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ openacs-4/packages/lamsint/www/admin/list.tcl	8 Dec 2005 09:41:08 -0000	1.1
@@ -0,0 +1,54 @@
+# packages/lamsint/www/list.tcl
+
+ad_page_contract {
+    
+    send LAMS learning deisgn list as a string seperated by ":" to client
+    
+    @author Ernie Ghiglione (ErnieG@melcoe.mq.edu.au)
+    @creation-date 2005-11-23
+    @arch-tag: 795e8952-ce5b-4d13-9129-17e3e8ce8174
+    @cvs-id $Id: list.tcl,v 1.1 2005/12/08 09:41:08 ernieg Exp $
+} {
+} -properties {
+} -validate {
+} -errors {
+}
+
+
+set datetime [lamsint::get_datetime]
+set lams_server_url [lamsint::get_lams_server_url]
+set server_id [lamsint::get_server_id]
+set username [ad_conn user_id]
+
+#set rawstring [string tolower [concat $datetime$username$server_id$server_key]]
+#set hash [string tolower [ns_sha1 $rawstring]]
+set hash [lamsint::ws::generate_hash -datetime $datetime -username $username]
+
+package require SOAP
+set uri "urn:lamsws"
+set proxy "$lams_server_url/services/LearningDesignService?wsdl"
+set action "$lams_server_url/services/LearningDesignService"
+
+SOAP::create lams_get_sequences \
+   -uri $uri \
+   -action $action \
+   -proxy $proxy \
+   -name "getAllLearningDesignsAsString" \
+    -params {"serverId" "string" "datetime" "string" "hashValue" "string" "username" "string"}
+
+set available_sequences [lams_get_sequences $server_id $datetime $hash $username]
+
+if {[regexp "AuthenticateException" $available_sequences]} {
+    ns_return 401 text/html ""
+    #ns_write "HTTP/1.1 401 Unauthenticated"
+    ad_script_abort
+} elseif {[regexp "ServerNotFoundException" $available_sequences]} {
+    ns_write "HTTP/1.1 417 Expectation Failed"
+    ad_script_abort
+} elseif {[string equal $available_sequences "NOT_SET_UP"]} {
+    ns_write "HTTP/1.1 402 Setup Required"
+    ad_script_abort
+}
+
+ns_write $available_sequences
+ad_script_abort