Commit cad95566 authored by Rinus Plasmeijer's avatar Rinus Plasmeijer
Browse files

*** empty log message ***


git-svn-id: https://svn.cs.ru.nl/repos/iTask-system/trunk@160 63da3aa8-80fd-4f01-9db8-e6ea747a3da2
parent 48a0cb4f
definition module InternaliTasksCommon
// *********************************************************************************************************************************
// internally used types and utility function
// *********************************************************************************************************************************
// iTask & iData Concept and Implementation: (c) 2006,2007,2008 - Rinus Plasmeijer
// *********************************************************************************************************************************
//
import iDataHandler, iDataFormData
import iTasksHandler
:: *TSt = { tasknr :: !TaskNr // for generating unique form-id's
, activated :: !Bool // if true activate task, if set as result task completed
, userId :: !Int // id of user to which task is assigned
, workflowLink :: !WorkflowLink // process table entry information
, staticInfo :: !StaticInfo // info which does not change during a run
, html :: !HtmlTree // accumulator for html code
, options :: !Options // iData lifespan and storage format
, trace :: !Maybe [Trace] // for displaying task trace
, hst :: !HSt // iData state
}
:: TaskNr :== [Int] // task nr i.j is adminstrated as [j,i]
:: WorkflowLink :== !(Entry,ProcessIds) // entry in table together with unique id which is used for checking whether the reference is still valid
:: Entry :== !Int
:: ProcessIds :== !(!UserId,!ProcessNr,!WorkflowLabel) // user id, process id and name given to a workflow process; is used as unique identifier in process table
:: UserId :== !Int // a user id of an iTask user must be a unique integer value
:: ProcessNr :== !Int
:: WorkflowLabel :== !String
:: StaticInfo = { currentUserId :: UserId // id of application user
, threadTableLoc:: !Lifespan // where to store the server thread table, default is Session
}
:: HtmlTree = BT HtmlCode // simple code
| (@@:) infix 0 TaskName HtmlTree // code with id of user attached to it
| (-@:) infix 0 UserId HtmlTree // skip code with this id if it is the id of the user
| (+-+) infixl 1 HtmlTree HtmlTree // code to be placed next to each other
| (+|+) infixl 1 HtmlTree HtmlTree // code to be placed below each other
| DivCode String HtmlTree // code that should be labeled with a div, used for Ajax and Client technology
:: Options = { tasklife :: !Lifespan // default: Session
, taskstorage :: !StorageFormat // default: PlainString
, taskmode :: !Mode // default: Edit
, gc :: !GarbageCollect // default: Collect
}
:: Trace = Trace !TraceInfo ![Trace] // traceinfo with possibly subprocess
:: TraceInfo :== Maybe !(!Bool,!(!UserId,!TaskNr,!Options,!String,!String)) // Task finished? who did it, task nr, task name (for tracing) value produced
:: TaskName :== !(!UserId,!ProcessNr,!WorkflowLabel,!TaskLabel) // id of user, workflow process name, task name
// Here follow some commonly used internal functions
/* Support for user defined combinators
mkTask :: for making a user defined combinator, name will appear intrace
*/
incNr :: !TaskNr -> TaskNr
mkTask :: !String !(Task a) -> Task a | iCreateAndPrint a
mkParSubTask :: !String !Int (Task a) -> (Task a) | iCreateAndPrint a // two shifts are needed
showTaskNr :: !TaskNr -> String
printTrace2 :: !(Maybe ![Trace]) -> BodyTag
iTaskId :: !Int !TaskNr !String -> String
deleteAllSubTasks :: ![TaskNr] TSt -> TSt
cFormId :: !Options !String !a -> FormId a
sessionFormId :: !Options !String !a -> FormId a
pageFormId :: !Options !String !a -> FormId a
storageFormId :: !Options !String !a -> FormId a
implementation module InternaliTasksCommon
// *********************************************************************************************************************************
// iTask & iData Concept and Implementation: (c) 2006,2007,2008 - Rinus Plasmeijer
// *********************************************************************************************************************************
//
import StdList, StdArray, StdFunc
import iDataHandler, iDataFormData, iDataTrivial
import iTasksSettings
import iTasksHandler, InternaliTasksThreadHandling
showTaskNr :: !TaskNr -> String
showTaskNr [] = ""
showTaskNr [i] = toString i
showTaskNr [i:is] = showTaskNr is <+++ "." <+++ toString i
iTaskId :: !Int !TaskNr !String -> String
iTaskId userid tasknr postfix
# postfix = { c \\ c <-: postfix | not (isMember c ['\\\"/:*?<>|"']) } // throw away characters not allowed in a file name
| postfix == ""
| userid < 0 = "iLog_" <+++ (showTaskNr tasknr)
| otherwise = "iTask_" <+++ (showTaskNr tasknr)
| userid < 0 = "iLog_" <+++ (showTaskNr tasknr) <+++ "-" <+++ postfix
| otherwise = "iTask_" <+++ (showTaskNr tasknr) <+++ "-" <+++ postfix // MJP:info removed to allow dynamic realloc of users: <+++ "+" <+++ userid
deleteAllSubTasks :: ![TaskNr] TSt -> TSt
deleteAllSubTasks [] tst = tst
deleteAllSubTasks [tx:txs] tst=:{hst,userId}
# hst = deleteIData (iTaskId userId (tl tx) "") hst
= deleteAllSubTasks txs {tst & hst = hst}
// ******************************************************************************************************
// Task creation and printing
// ******************************************************************************************************
incTaskNr tst = {tst & tasknr = incNr tst.tasknr}
incNr :: !TaskNr -> TaskNr
incNr [] = [0]
incNr [i:is] = [i+1:is]
// mkTask is an important wrapper function which should be wrapped around any task
// It takes care of
// - deciding whether the task should be called (activated) or not
// - adding of trace information
// - generating task numbers in a systematic way
// It is very important that the numbering of the tasks is done systematically
// Every task should have a unique number
// Every sequential task should increase the task number
// If a task j is a subtask of task i, than it will get number i.j in reverse order
mkTask :: !String !(Task a) -> (Task a) | iCreateAndPrint a
mkTask taskname mytask = mkTaskNoInc taskname mytask o incTaskNr
mkTaskNoInc :: !String !(Task a) -> (Task a) | iCreateAndPrint a // common second part of task wrappers
mkTaskNoInc taskname mytask = mkTaskNoInc`
where
mkTaskNoInc` tst=:{activated,tasknr,userId,options}
| not activated = (createDefault,tst) // not active, don't call task, return default value
# (val,tst=:{activated,trace}) = mytask tst // active, so perform task and get its result
# tst = {tst & tasknr = tasknr, options = options, userId = userId}
| isNothing trace || taskname == "" = (val,tst) // no trace, just return value
= (val,{tst & trace = Just (InsertTrace activated tasknr userId options taskname (printToString val%(0,30)) (fromJust trace))}) // adjust trace, don't print to long values
mkParSubTask :: !String !Int (Task a) -> (Task a) | iCreateAndPrint a // two shifts are needed
mkParSubTask name i task = mkParSubTask`
where
mkParSubTask` tst=:{tasknr, options}
# (v,tst) = mkTaskNoInc (name <+++ "." <+++ i) mysubtask {tst & tasknr = [i:tasknr],activated = True} // shift task
= (v,{tst & tasknr = tasknr, options = options})
where
mysubtask tst=:{tasknr} = task {tst & tasknr = [-1:tasknr], activated = True} // shift once again!
// ******************************************************************************************************
// Trace Printing...
// ******************************************************************************************************
InsertTrace :: !Bool !TaskNr !Int !Options String !String ![Trace] -> [Trace]
InsertTrace finished idx who options taskname val trace = InsertTrace` ridx who val trace
where
InsertTrace` :: !TaskNr !Int !String ![Trace] -> [Trace]
InsertTrace` [i] who str traces
| i < 0 = abort ("negative task numbers:" <+++ showTaskNr idx <+++ "," <+++ who <+++ "," <+++ taskname)
# (Trace _ itraces) = select i traces
= updateAt` i (Trace (Just (finished,(who,show,options,taskname,str))) itraces) traces
InsertTrace` [i:is] who str traces
| i < 0 = abort ("negative task numbers:" <+++ showTaskNr idx <+++ "," <+++ who <+++ "," <+++ taskname)
# (Trace ni itraces) = select i traces
# nistraces = InsertTrace` is who str itraces
= updateAt` i (Trace ni nistraces) traces
select :: !Int ![Trace] -> Trace
select i list
| i < length list = list!!i
= Trace Nothing []
show = idx //showTaskNr idx
ridx = reverse idx
updateAt`:: !Int !Trace ![Trace] -> [Trace]
updateAt` n x list
| n < 0 = abort "negative numbers not allowed"
= updateAt` n x list
where
updateAt`:: !Int !Trace ![Trace] -> [Trace]
updateAt` 0 x [] = [x]
updateAt` 0 x [y:ys] = [x:ys]
updateAt` n x [] = [Trace Nothing [] : updateAt` (n-1) x []]
updateAt` n x [y:ys] = [y : updateAt` (n-1) x ys]
printTrace2 :: !(Maybe ![Trace]) -> BodyTag
printTrace2 Nothing = EmptyBody
printTrace2 (Just a) = BodyTag [showLabel "Task Tree Forest:", Br, STable emptyBackground (print False a),Hr []]
where
print _ [] = []
print b trace = [pr b x ++ [STable emptyBackground (print (isDone x||b) xs)]\\ (Trace x xs) <- trace]
pr _ Nothing = []
pr dprev (Just (dtask,(w,i,op,tn,s)))
| dprev && (not dtask) = pr False Nothing // subtask not important anymore (assume no milestone tasks)
| not dtask && tn%(0,4) == "Ajax " = showTask cellattr1b White Navy Aqua Silver (w,i,op,tn,s)
| not dtask && tn%(0,6) == "Server " = showTask cellattr1b White Navy Aqua Silver (w,i,op,tn,s)
| not dtask && tn%(0,6) == "Client " = showTask cellattr1b White Navy Aqua Silver (w,i,op,tn,s)
| not dtask = showTask cellattr1b White Navy Maroon Silver (w,i,op,tn,s)
= showTask cellattr1a White Yellow Red White (w,i,op,tn,s)
showTask2 attr1 c1 c2 c3 c4 (w,i,op,tn,s)
= [Table doneBackground [ Tr [] [Td attr1 [font c1 (toString (last (reverse i)))], Td cellattr2 [font c2 tn]]
, Tr [] [Td attr1 [font c3 (toString w)], Td cellattr2 [font c4 s]]
]
,Br]
showTask att c1 c2 c3 c4 (w,i,op,tn,s)
= [STable doneBackground
[ [font c1 (toString w),font c2 ("T" <+++ showTaskNr i)]
, [showStorage op.tasklife, font c3 tn]
, [EmptyBody, font c4 s]
]
]
isDone Nothing = False
isDone (Just (b,(w,i,op,tn,s))) = b
showStorage Temp = font Silver "Tmp"
showStorage Client = font Aqua "Cli"
showStorage Page = font Navy "Pag"
showStorage Session = font Navy "Ssn"
showStorage TxtFileRO = font Red "TxF0"
showStorage TxtFile = font Red "TxF"
showStorage DataFile = font Red "DaF"
showStorage Database = font Red "DaB"
doneBackground = [ Tbl_CellPadding (Pixels 1), Tbl_CellSpacing (Pixels 0), cellwidth
, Tbl_Rules Rul_None, Tbl_Frame Frm_Border
]
doneBackground2 = [ Tbl_CellPadding (Pixels 0), Tbl_CellSpacing (Pixels 0), cellwidth
]
emptyBackground = [Tbl_CellPadding (Pixels 0), Tbl_CellSpacing (Pixels 0)]
cellattr1a = [Td_Bgcolor (`Colorname Green), Td_Width (Pixels 10), Td_VAlign Alo_Absmiddle]
cellattr1b = [Td_Bgcolor (`Colorname Silver), Td_Width (Pixels 10), Td_VAlign Alo_Absmiddle]
cellattr2 = [Td_VAlign Alo_Top]
cellwidth = Tbl_Width (Pixels 130)
font color message
= Font [Fnt_Color (`Colorname color), Fnt_Size -1] [B [] message]
// ******************************************************************************************************
// iTask Storage Utilities
// ******************************************************************************************************
cFormId :: !Options !String !a -> FormId a
cFormId {tasklife,taskstorage,taskmode} s d = {sFormId s d & lifespan = tasklife, storage = taskstorage, mode = taskmode}
sessionFormId :: !Options !String !a -> FormId a
sessionFormId options s d = cFormId options s d <@ if (options.tasklife == Client) Client Session
pageFormId :: !Options !String !a -> FormId a
pageFormId options s d = cFormId options s d <@ if (options.tasklife == Client) Client Page
storageFormId :: !Options !String !a -> FormId a
storageFormId options s d = cFormId options s d <@ NoForm
definition module InternaliTasksThreadHandling
// *********************************************************************************************************************************
// internally used function for Ajax and Client thread handling
// *********************************************************************************************************************************
// iTask & iData Concept and Implementation: (c) 2006,2007,2008 - Rinus Plasmeijer
// *********************************************************************************************************************************
//
import InternaliTasksCommon
:: ThreadTable :== [TaskThread] // thread table is used for Ajax and OnClient options
:: TaskThread = { thrTaskNr :: !TaskNr // task number to recover
, thrUserId :: !UserId // which user has to perform the task
, thrWorkflowLink :: !WorkflowLink// what was the name of workflow process it was part off
, thrOptions :: !Options // options of the task
, thrCallback :: !String // serialized callback function for the server
, thrCallbackClient :: !String // serialized callback function for the client (optional, empty if not applicable)
, thrKind :: !ThreadKind // kind of thread
, thrVersionNr :: !Int // version number of application when thread was created
}
:: ThreadKind = ServerThread // Thread which can only be executed on Server
| ClientServerThread // Thread preferably to be executed on Client, but also runs on Server
| ClientThread // Thread which can only be executed on the Client
| ExceptionHandler // Exception handler only works on server
| AnyThread // Used for garbage collection
:: GlobalInfo = { versionNr :: !Int // latest querie number of a user
, newThread :: !Bool // is a new thread assigned to this user (used for Ajax)?
, deletedThreads :: ![TaskNr] // are there threads deleted (used for Ajax)?
}
instance == ThreadKind
showThreadNr :: !TaskNr -> String
showThreadTable :: *TSt -> (HtmlCode,*TSt) // watch it: the actual threadnumber stored is one level deaper, so [-1:nr] instead of nr !!
setPUser :: !Int !(GlobalInfo -> GlobalInfo) !*HSt -> (!GlobalInfo,!*HSt)
setPUserNr :: !Int !(Int -> Int) !*HSt -> (!GlobalInfo,!*HSt)
clearIncPUser :: !Int !(Int -> Int) !*HSt -> (!GlobalInfo,!*HSt)
administrateNewThread :: UserId *TSt -> *TSt
mkTaskThread :: !SubPage !(Task a) -> Task a | iData a
mkTaskThread2 :: !ThreadKind !(Task a) -> Task a // execute a thread
evalTaskThread :: !TaskThread -> Task a // execute the thread !!!!
ThreadTableStorage :: !(ThreadTable -> ThreadTable) -> (Task ThreadTable) // used to store Tasknr of callbackfunctions / threads
ServerThreadTableStorage :: !(ThreadTable -> ThreadTable) -> (Task ThreadTable) // used to store Tasknr of callbackfunctions / threads
ClientThreadTableStorage :: !(ThreadTable -> ThreadTable) -> (Task ThreadTable) // used to store Tasknr of callbackfunctions / threads
ThreadTableStorageGen :: !String !Lifespan !(ThreadTable -> ThreadTable) -> (Task ThreadTable)// used to store Tasknr of callbackfunctions / threads
copyThreadTableToClient :: !*TSt -> !*TSt // copies all threads for this user from server to client thread table
splitServerThreadsByUser :: !*TSt -> !(!(!ThreadTable,!ThreadTable),!*TSt) // get all threads from a given user from the server thread table
copyThreadTableFromClient :: !GlobalInfo !*TSt -> !*TSt // copies all threads for this user from client to server thread table
findThreadInTable :: !ThreadKind !TaskNr *TSt -> *(Maybe (!Int,!TaskThread),*TSt) // find thread that belongs to given tasknr
insertNewThread :: !TaskThread *TSt -> *TSt // insert new thread in table
deleteThreads :: !TaskNr !*TSt -> *TSt
findParentThread :: !TaskNr !*TSt -> *([TaskThread],*TSt) // finds parent thread closest to given set of task numbers
serializeThread :: !.(Task .a) -> .String
deserializeThread :: .String -> .(Task .a)
serializeThreadClient :: !(Task a) -> String
deserializeThreadClient :: .String -> .(Task .a)
deleteSubTasksAndThreads :: !TaskNr TSt -> TSt
deleteAllSubTasksAndThreads :: ![TaskNr] TSt -> TSt
This diff is collapsed.
definition module StdiTasks
// *********************************************************************************************************************************
// Main iTask pass thru module exporting all End User iTask modules
// (c) iTask & iData Concept and Implementation by Rinus Plasmeijer, 2006-2008 - MJP
// *********************************************************************************************************************************
// iTask & iData Concept and Implementation: (c) 2006,2007,2008 - Rinus Plasmeijer
// *********************************************************************************************************************************
//
import
// iTask End User modules:
iTasks // iTask main module and core engine
, iTasks2 // commonly used iTask combinators
, iTasksDB // iTask simple DB access
, iTasksSettings // font settings
iTasksHandler // iTask main module and core engine
, iTasksProcessHandling // creation of iTask Workflow Processes
, iTasksEditors // basic html editors for any type
, iTasksHtmlSupport // html prompting
, iTasksBasicCombinators // basic iTask combinators
, iTasksCombinators // handy set of additional iTask combinators
, iTasksTimeAndDateHandling // iTasks triggered by time and date
, iTasksExceptionHandling // for handling exceptional situations
, iTasksLiftingCombinators // lifting other domains (e.g. iData) to the iTask domain
, iTasksDB // iTask simple DB access
, iTasksSettings // font settings
definition module iTasksBasicCombinators
// *********************************************************************************************************************************
// This module contains the basic iTasks combinators
// *********************************************************************************************************************************
// iTask & iData Concept and Implementation: (c) 2006,2007,2008 - Rinus Plasmeijer
// *********************************************************************************************************************************
//
import iTasksHandler
:: TCl a = TCl !.(Task a) // task closure, container for a task used for higher order tasks (task which deliver a task)
:: ChoiceUpdate :== !Bool [Bool] -> [Bool] // changed checkbox + current settings -> new settings
derive gForm TCl
derive gUpd TCl
derive gPrint TCl
derive gParse TCl
derive read TCl
derive write TCl
/*
Standard monadic combinators on iTasks:
(=>>) :: for sequencing: bind
return_V :: lift a value to the iTask domain and return it
*/
(=>>) infixl 1 :: !(Task a) !(a -> Task b) -> Task b | iCreateAndPrint b
return_V :: !a -> Task a | iCreateAndPrint a
/*
Assign tasks to user with indicated id:
assignTaskTo :: assign task to indicated user, True for verbose reporting
*/
assignTaskTo :: !Bool !UserId !(LabeledTask a) -> Task a | iData a
/*
Repetition and loops:
foreverTask :: infinitely repeating Task
(<!) :: repeat task (as a loop) as long as predicate does not hold; also works for tasks that don't require any user interactions (e.g. database access)
*/
foreverTask :: !(Task a) -> Task a | iData a
(<!) infixl 6 :: !(Task a) !(a -> .Bool) -> Task a | iCreateAndPrint a
/*
Sequencing Tasks:
seqTasks :: do all iTasks one after another, task completed when all done
*/
seqTasks :: ![LabeledTask a] -> Task [a] | iCreateAndPrint a
/*
Choose the tasks you want to do one forehand:
chooseTask_btn :: choose ONE task by pressing a button, True for horizontal buttons, else vertical
chooseTask_pdm :: as chooseTask_btn, depending on pulldownmenu item selected, Int for initial value
chooseTask_radio:: as chooseTask_btn, depending on radio item selected, Int for initial value, htmlcode for option explanation
chooseTask_cb :: choice N tasks out of N, order of chosen task depending on first arg
(initial setting, effect for all when set, explanation) for each option
*/
chooseTask_btn :: !HtmlCode !Bool![LabeledTask a] -> Task a | iCreateAndPrint a
chooseTask_pdm :: !HtmlCode !Int ![LabeledTask a] -> Task a | iCreateAndPrint a
chooseTask_radio:: !HtmlCode !Int ![(HtmlCode,LabeledTask a)]
-> Task a | iCreateAndPrint a
chooseTask_cbox :: !([LabeledTask a] -> Task [a])
!HtmlCode ![((!Bool,!ChoiceUpdate,!HtmlCode),LabeledTask a)]
-> Task [a] | iData a
/*
Do m Tasks parallel / interleaved and FINISH as soon as SOME Task completes:
orTask2 :: do both iTasks in any order, combined task completed as any subtask is done
andTask2 :: do both iTasks in any order (interleaved), task completed when both done
andTasksCond :: do tasks in any order until pred holds for finished tasks, string used for naming group of task navigation buttons
*/
orTask2 :: !(Task a,Task b) -> Task (EITHER a b)
| iCreateAndPrint a & iCreateAndPrint b
andTask2 :: !(Task a,Task b) -> Task (a,b) | iCreateAndPrint a & iCreateAndPrint b
andTasksCond :: !String !([a] -> Bool) ![LabeledTask a] -> (Task [a]) | iData a
/* Support for user defined combinators
newTask :: same, but optimized: after completion only result will remembered
Once :: task will be done only once, the value of the task will be remembered, important for side effecting functions lifted to iData domain
*/
newTask :: !String !(Task a) -> Task a | iData a
Once :: !String !(Task a) -> Task a | iData a
/* Operations on Task state
taskId :: give id of user assigned to task
userId :: give id of application user
*/
//taskId :: TSt -> (Int,TSt)
//userId :: TSt -> (Int,TSt)
/* Experimental department:
May not work when the tasks are garbage collected !!
-!> :: a task, either finished or interrupted (by completion of the first task) is returned in the closure
if interrupted, the work done so far is returned (!) which can be continued somewhere else
channel :: splits a task in respectively a sender task closure and receiver taskclosure;
when the sender is evaluated, the original task is evaluated as usual;
when the receiver task is evaluated, it will wait upon completeion of the sender and then get's its result;
Important: Notice that a receiver will never finish if you don't activate the corresponding receiver somewhere.
*/
(-!>) infix 4 :: (Task stop) (Task a) -> Task (Maybe stop,TCl a) | iCreateAndPrint stop & iCreateAndPrint a
channel :: String (Task a) -> Task (TCl a,TCl a) | iCreateAndPrint a
This diff is collapsed.
definition module iTasksCombinators
// *********************************************************************************************************************************
// This module contains a collection of handy iTasks combinators defined in terms of the basic iTask combinators
// with Thanks to Erik Zuurbier for suggesting some of the advanced combinators
// *********************************************************************************************************************************
// iTask & iData Concept and Implementation: (c) 2006,2007,2008 - Rinus Plasmeijer
// *********************************************************************************************************************************
//
import iTasksBasicCombinators
/* standard monadic combinators on iTasks:
(#>>) :: for sequencing: bind, but no argument passed
return_D :: return the value and show it in iData display format
return_VF :: return the value and show the Html code specified
*/
(#>>) infixl 1 :: !(Task a) !(Task b) -> Task b | iCreateAndPrint b
return_D :: !a -> Task a | gForm {|*|}, iCreateAndPrint a
return_VF :: !HtmlCode !a -> Task a | iCreateAndPrint a
/* Assign tasks to user with indicated id:
(@:) :: will prompt who is waiting for task with give name
(@::) :: as @:, a default task name is chosen as label
(@:>) :: as @:, no prompting
(@::>) :: as @::, no prompting
*/
(@:) infix 3 :: !UserId !(LabeledTask a) -> Task a | iData a
(@::) infix 3 :: !UserId !(Task a) -> Task a | iData a
(@:>) infix 3 :: !UserId !(LabeledTask a) -> Task a | iData a
(@::>) infix 3 :: !UserId !(Task a) -> Task a | iData a
/* Handling recursion and loops:
repeatTask :: repeat Task until predicate is valid
(<|) :: repeat task (recursively) as long as predicate does not hold, and give error message otherwise
*/
repeatTask :: !(a -> Task a) !(a -> Bool) a -> Task a | iData a
(<|) infixl 6 :: !(Task a) !(a -> (Bool, HtmlCode)) -> Task a | iData a
/* Choose out the tasks you want to do one forehand, labels are used to make the choice:
button :: return value when button pressed
buttonTask :: do the iTask when button pressed
chooseTask :: Choose ONE iTask from list, depending on button pressed, button horizontal displayed
chooseTaskV :: as chooseTask, buttons vertical displayed
mchoiceTask :: Checked tasks will be done SEQUENTIALLY
mchoiceTask2 :: as mchoiceTask, boolean used for initial setting of the checks
mchoiceTask3 :: as mchoiceTask2, function can be used to (re)set the checkboxes
mchoiceTask :: Checked tasks can be done in INTERLEAVED
mchoiceTask2 :: as mchoiceTask, boolean used for initial setting of the checks
mchoiceTask3 :: as mchoiceTask2, function can be used to (re)set the checkboxes
*/
button :: !String !a -> Task a | iCreateAndPrint a
buttonTask :: !String !(Task a) -> Task a | iCreateAndPrint a
chooseTask :: !HtmlCode ![LabeledTask a] -> Task a | iCreateAndPrint a
chooseTaskV :: !HtmlCode ![LabeledTask a] -> Task a | iCreateAndPrint a
mchoiceTasks :: !HtmlCode ![LabeledTask a] -> Task [a] | iData a
mchoiceTasks2 :: !HtmlCode ![(!Bool,LabeledTask a)] -> Task [a] | iData a
mchoiceTasks3 :: !HtmlCode ![((!Bool,!ChoiceUpdate,!HtmlCode),LabeledTask a)]
-> Task [a] | iData a
mchoiceAndTasks :: !HtmlCode ![LabeledTask a] -> Task [a] | iData a
mchoiceAndTasks2:: !HtmlCode ![(!Bool,LabeledTask a)] -> Task [a] | iData a
mchoiceAndTasks3 :: !HtmlCode ![((!Bool,!ChoiceUpdate,!HtmlCode),LabeledTask a)]
-> Task [a] | iData a
/* Do m Tasks parallel / interleaved and FINISH as soon as SOME Task completes:
(-||-) :: do both iTasks in any order, combined task completed as soon as any subtask is done
(-&&-) :: do both iTasks in any order (interleaved), task completed when both done
orTasks :: do all iTasks in any order (interleaved), task completed as soon as any subtask is done
andTasks :: do all iTasks in any order (interleaved), task completed when all done
andTasks_mu :: assign task to indicated users, task completed when all done
*/
(-||-) infixr 3 :: !(Task a) !(Task a) -> Task a | iData a
(-&&-) infixr 4 :: !(Task a) !(Task b) -> Task (a,b) | iData a & iData b
orTasks :: ![LabeledTask a] -> (Task a) | iData a
andTasks :: ![LabeledTask a] -> Task [a] | iData a
andTasks_mu :: !String ![(Int,Task a)] -> Task [a] | iData a
/* convenient combinators for tasks that maybe return a result: