F)$v      !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~ None       NoneYa Token identifies a flow that handle messages. The scheduler compose a Token with every  C message that arrives and send the mesage to the appropriate flow. JList of (wfname, workflow) pairs, to be scheduled depending on the message' s pwfname The anonymous user  It is the path of the root flow #send a complete response %Qsend a response fragment. Useful for streaming. the last packet must sent trough # +Texecutes a simple monadic computation that receive the params and return a response It is used with - hackMessageFlow or waiMessageFlow ,HExecutes a monadic computation that send and receive messages, but does X not store its state in permanent storage. The process once stopped, will restart anew -Fadd a list of flows to be scheduled. Each entry in the list is a pair  (path, flow) .!return the list of the scheduler /)The scheduler creates a Token with every  T message that arrives and send the mesage to the appropriate flow, get the response  and return it. 0The handler of the error log 1 set the 404  not found response 3OWrites a XML tag in a ByteString. It is the most basic form of formatting. For % more sophisticated formatting , use MFlow.Forms.XHtml or MFlow.Forms.HSP. 4  bhtml ats v= btag "html" ats v 5  bbody ats v= btag "body" ats v C  !"#$%&'()*+,-./012345,  !"#$%&'()*+,-./012345, (')*#$%&-.,+ 012345 !"/2   !"#$%&'()*+,-./012345None>7SMinimal interface for defining the basic form combinators in a concrete rendering.  defined in this module. see MFlow.Forms.XHtml for the instance for  Text.XHtml% and MFlow.Forms.HSP for an instance  form Haskell Server Pages. EA FormLet instance  return the key name of an user KRegister an user/ password LAuthentication against K ed users.  to be used with S ONUse this instead of return to return from a computation with an ask statement TThis way when the user press the back button, the computation will execute back, to 8 the returned code, according with the user navigation. PnCached widgets operate with widgets in the Identity monad, but they may perform IO using the execute instance B of the monad m, which is usually the IO monad. execute basically " sanctifies"4 the use of unsafePerformIO for a transient purpose % such is caching. This is defined in Data.TCache.Memoization. The user can create his  own instance for his monad. With P] it is possible to cache the rendering of a widget as a ByteString (maintaining type safety) , permanently or for a certain time. this is very useful for complex widgets that present information. Specially it they must access to databases.    import Mflow.Wai.XHtm.All  import Some.Time.Library . main= run 80 waiMessageFlow [(noscript, time)]  time=do ask $ cachedWidget "time" 5  $ wlink () bold << " the time is "" ++ show (execute giveTheTime) ++ " click here"  time [this pseudocode would update the time every 5 seconds. The execution of the IO computation Z giveTheTime must be executed inside the cached widget to avoid unnecesary IO executions. Q Execute the  FlowM view m# monad. It is used as parameter of hackMessageFlow waiMessageFlow or -  main= do ' forkIO $ run 80 $ waiMessageFlow [("noscript",transient $ runFlow mainf)]  adminLoop SAValidates a form or widget result against a validating procedure getOdd= getInt Nothing S (x3 -> return $ if mod x 2==0 then Nothing else Just only odd numbers, please)TDActions are callbacks that are executed when a widget is validated. _ It is useful when the widget is inside widget containers that know nothing about his content. J It returns a result that can be significative or, else, be ignored with y and x. D An action may or may not initiate his own dialog with the user via z UIA modifier get the result and the rendering of a widget and change them. ^This modifier, when logged, changes a login-password-register widget with a display username. userFormOrName= t Nothing o `wmodify` f  where  f _ justu@(Just u) = return ([9 u]4, justu) -- user validated, display and return user  f felem Nothing = do  us <- n  if us ==  ` then return (felem, Nothing) -- user not logged, present the form  else return([9 us]=, Just us) -- already logged, display and return userV'display a text box and return a String Whdisplay a text box and return an Integer (if the value entered is not an Integer, fails the validation) X_display a text box and return a Int (if the value entered is not an Int, fails the validation) Ydisplay a password box Z=implement a radio button that perform a submit when pressed. . the parameter is the name of the radio group [implement a radio button . the parameter is the name of the radio group \cdisplay a text box and return the value entered if it is readable( Otherwise, fail the validation) `4display a multiline text box and return its content aVdisplay a dropdown box with the two values (second (true) and third parameter(false)) E . With the value of the first parameter selected. bVdisplay a dropdown box with the options in the first parameter is optionally selected $ . It returns the selected option. c<set the option for getSelect. Options are concatenated with  dEset the selected option for getSelect. Options are concatenated with  e#Enclose Widgets in some formating.  view7 is intended to be instantiated to a particular format DThis is a widget, which is table with some links. it returns an Int  import MFlow.Forms.XHtml   tableLinks :: View Html Int X tableLinks= table ! [border 1,thestyle "width:20%;margin-left:auto;margin-right:auto"] . <<< caption << "choose an item" a ++> thead << tr << concatHtml[ th << bold << "item", th << bold << "times chosen"]  ++> (tbody ] <<< (tr <<< td <<< wlink 0 (bold <<"iphone") <++ td << ( bold << "One") ] <|> tr <<< td <<< wlink 1 (bold <<"ipad") <++ td << ( bold << "Two") ` <|> tr <<< td <<< wlink 2 (bold <<"ipod") <++ td << ( bold << "Three"))  ) f:Useful for the creation of pages using two or more views.  For example HSP and Html. J Because both have ConvertTo instances to ByteString, then it is possible  to mix them via f:  ) normalize widget <+> normalize widget' is equivalent to  widget .<+>. widget' g#Append formatting code to a widget  getString hi <++ H1 << hi thereh$Prepend formatting code to a widget bold  <"enter name" ++ getString Nothingi#add attributes to the form element D if the view has more than one element, it is applied to the first jPSet the header-footer that will enclose the widgets. It must be provided in the b same formatting than them, altrough with normalization to byteStrings can be used any formatting 2This header uses XML trough Haskell Server Pages ( &http://hackage.haskell.org/package/hsp)    setHeader $ c ->  <html>  <head>  <title> my title </title>  < meta name= "Keywords" content= "sci-fi" />)  </head>  < body style= "margin-left:5%;margin-right:5%">  <% c %>  </body>  </html> This header uses  Text.XHtml    setHeader $ c ->  thehtml  << (header  << (thetitle << title +++  meta ! [name "Keywords" ,content "sci-fi"])) +++  body ! [style "margin-left:5%;margin-right:5%"] c /This header uses both. It uses byteString tags   setHeader $ c ->  4 [] $  3 head [] $  (D (thetitle << title)   D  meta(name= \"Keywords\" content= \"sci-fi\" /)   5 [("style", "margin-left:5%;margin-right:5%")] c kreturn the current header lSet an HTTP cookie mJSet 1) the timeout of the flow execution since the last user interaction. K Once passed, the flow executes from the begining. 2). In persistent flows K it set the session state timeout for the flow, that is persistent. If the + flow is not persistent, it has no effect. , flows restart anew.  persistent flows (that use 3) restart at the las saved execution point, unless , the session time has expired for the user. oIs an example of login/#register validation form needed by t. In this case [ the form field appears in a single line. it shows, in sequence, entries for the username, T password, a button for loging, a entry to repeat password necesary for registering  and a button for registering. & The user can build its own user login/+validation forms by modifying this example  userFormLine=  (User <$> getString (Just " enter user") <*> getPassword <+> submitButton "login")  <+> fromString " password again" +> getPassword <* submitButton "register" pExample of user/.password form (no validation) to be used with t q1empty widget that return Nothing. May be used as " empty boxes" inside larger widgets rFrender the Show instance of the parameter and return it. It is useful  for displaying information s*Wether the user is logged or is anonymous t"It creates a widget for user login/)registering. If a user name is specified . in the first parameter, it is forced to login/ password as this specific user. F Otherwise, if the user is already logged, the widget does not appear 0 If the user press the register button, the user/password is registered and the  user u8If not logged, perform login. otherwise return the user +getUserSimple= getUser Nothing userFormLinev@Very basic user authentication. The user is stored in a cookie. A it looks for the cookie. If no cookie, it ask to the user for a Ked  user-password combination. P The user-password combination is only asked if the user has not logged already - otherwise, the stored username is returned. )getUser mu form= ask $ userWidget mu form"Join two widgets in the same page  the resulting widget, when z.ed with it, returns a either one or the other , r <- ask widget widget1 <+> widget widget2 # case r of (Just x, Nothing) -> .. w"Join two widgets in the same page  the resulting widget, when z.ed with it, returns a either one or the other , r <- ask widget widget1 <+> widget widget2 # case r of (Just x, Nothing) -> .. x\The first elem result (even if it is not validated) is discarded, and the secod is returned / . This contrast with the applicative operator % which fails the whole validation if ) the validation of the first elem fails. = . The first element is displayed however, as in the case of  y]The second elem result (even if it is not validated) is discarded, and the first is returned / . This contrast with the applicative operator % which fails the whole validation if * the validation of the second elem fails. = . The first element is displayed however, as in the case of  z)It is the way to interact with the user. . It takes a widget and return the user result + If the environment has the result, ask don't ask to the user. % To force asking in any case, put an | statement before  in the FlowM monad {\True if the flow is going back (as a result of the back button pressed in the web browser). P Usually this chech is nos necessary unless conditional code make it necessary   menu= do  mop <- getGoStraighTo  case mop of  Just goop -> goop  Nothing -> do  r <- z option1 < |> option2  case r of < op1 -> setGoStraighTo (Just goop1) >> goop1 ; op2 -> setGoStraighTo (Just goop2) >> goop2RThis pseudocode would execute the ask of the menu once. But if the user press the R back button he will see again the menu. To let him choose other option, the code  has to be change to  menu= do  mop <- getGoStraighTo  back <- {  case (mop,back) of " (Just goop,False) -> goop  _ -> do  r <- z option1 < |> option2  case r of < op1 -> setGoStraighTo (Just goop1) >> goop1 ; op2 -> setGoStraighTo (Just goop2) >> goop2|Clears the environment }<wrap a widget of form element within a form-action element. Icreates a link wiget. A link can be composed with other widget elements, EConcat a list of widgets of the same type, to return a single result Rintersperse a widget in a list of widgets. the results is a 2-tuple of both types KPut a widget above and below other. Useful for navigation links in a page. AFlatten a binary tree of tuples of Maybe results produced by the < +> operator ? into a single tuple with the same elements in the same order. 2 This is useful for easing matching. For example:   res <- ask $ wlink1 <+> wlink2 wform < +> wlink3 < +> wlink4res has type:  GMaybe (Maybe (Maybe (Maybe (Maybe a,Maybe b),Maybe c),Maybe d),Maybe e)but  flatten res has type: . (Maybe a, Maybe b, Maybe c, Maybe d, Maybe e) ! (.<<.) w x = w $ toByteString x + (.<+>.) x y = normalize x <+> normalize y / (.|*>.) x y = normalize x |*> map normalize y + (.|+|.) x y = normalize x |+| normalize y + (.**>.) x y = normalize x **> normalize y + (.<**.) x y = normalize x <** normalize y * (.<|>.) x y= normalize x <|> normalize y - (.<++.) x v= normalize x <++ toByteString v - (.++>.) v x= toByteString v ++> normalize x 6789:;<=>?@ABCDEFGHIJKLMNOP/The key of the cached object for the retrieval /Timeout of the caching. Zero means sessionwide )The cached widget, in the Identity monad The cached result QRSTUVWXYZ[\]^_`abcdefghijklname value path 1Max-Age in seconds. Nothing for a session cookie mnopqrstuvwxyz{|}~      !"_3456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~_EFHG789:;<=>?@ABKLsIJMNnuvoptz|VXW]`abcdY[Z\~}_SqrTUPwxyeghi345fCDQR{Ojkml6^67 89:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~      !" None#$%&#$%&None0A small console interpreter with some commands:  sync4 Synchronize the cache with persistent storage (see ') flush Flush the cache end Synchronize and exit abort Exit. Do not synchronize 8on exception, for example Control-c, it sync and exits. > It must be used as the last statement of the main procedure. 7Install the admin flow in the list of flows handled by HackMessageFlow @ this gives access to an administrator page. It is necessary to  create an admin user with M. 1The administration page is reached with the path  adminserv ()*+,-. ()*+,-.NoneWSet the path of the files in the web server. The links to the files are relative to it TIs the flow to be added to the list in order to stream any file from the filesystem  for example, images 'This app includes the fileServe flow:    addFileServerWF * run 80 $ hackMessageFlow messageFlows  adminLoop  where  messageFlows= [(noscript$ , transient $ runFlow showStories)  ,(admin! , transient $ runFlow admin)  ,(mail , transient $ runFlow mail)]1| Add the fileServer to the list of server flows ECreates the url of file path. To be used in ordinary links to files. , in Text.XHtml, a image would be embeded as  # image ![src $ linkFile imagepath] in HSP: ! <img src=(linkFile imagepath)\> @Given the relative path of a file, it return the content of the href element in a html link /0123/0123NoneLInstall the server code and return the client code for an AJAX interaction. ajaxHead must be used instead of 4 when using ajax(see example). Although it produces code form  Text.XHtml rendering (package xhtml), [ it can be converted to byteString, so that any rendering can be used trough normalization  . see j >The javScript variable whose value will be sent to the server -The server procedure to be executed with the A variable value as parameter. It must return a string with valid . javaScript code to be executed in the client >return the javascript of the event handler, to be inserted in $ the HTML to be sent to the client None56789: 56789:None;An instance of the abstract MFlow scheduler to the  &http://hackage.haskell.org/package/wai interface. Iit accept the list of processes being scheduled and return a wai handler  Example:  main= do   putStrLn $ options messageFlows  run 80 $  messageFlows  where  messageFlows= [("main", runFlow flowname )  ,("hello", + statelesproc)  ,("trans", , $ runflow transientflow]  options msgs= "in the browser choose\n\n" ++  concat [ http://server/++ i ++ n | (i,_) <- msgs]   6waiMessageFlow :: [(String, (Token -> Workflow IO ()))] 6 -> (Request -> ResourceT IO Response)  waiMessageFlow messageFlows = 0 unsafePerformIO (addMessageFlows messageFlows) < ' waiWorkflow -- wFMiddleware f other =>?@A;BCDEFGH3  !"#$%&'()*+,-./012345 =>?@A;BCDEFGH NoneIJKLMNO'PQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~      !"#$%&'()*+,-.4/0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~  !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~   !"#$%&'()*+,+-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~ `DUW      !"#$%& ' ( ) *+,-./0123456789:;<=>?@ABCDEFGGHIJKLMNOPQR+,S+,T+,U+,V+,W+,X+,Y+,Z+,[+,\+,]+,^+,_+,`+,a+,b+,c+,d+,e+,f+,g+,h+,i+,j+,k+,l+,m+,n+,o+,p+,q+,r+,s+,t+uv+wx+yz+y{+y|+y}+y~+y+y+y+y+y+y+y+y:::::::::::::::::::::: : : : : :::::::::;:;:;:;:;:;:;:;:;:;:;:; :;!:;":;#:;$:;%:;&:;':;(:;):;*:;+:;,:;-:;.:;/:;0:;1:;2:;3:;4:;5:;6:;7:;8:;9:;::;;:;<:;=:;>:;?:;@:;A:;B:;C:;D:;E:;F:;G:;H:;I:;J:;K:;L:;M:;N:;O:;P:;Q:;R:;S:;T:;U:;V:;W:;X:;Y:;Z:;[:;\:;]:;^:;_:;`:ab:ac:ad:ae:af:ag:ah:ai:aj:ak:al:am:an:ao:ap:aq:ar:as:at:au:av:aw:ax:ay:az:a{:a|:a}:a~:a:a:a:a:a:a:a:a:a:a:a:a:a:a:a:a:a:a:a:::::::::::::::::::::::::: MFlow-0.1.5.2MFlow MFlow.Forms MFlow.CookiesMFlow.Forms.AdminMFlow.FileServerMFlow.Forms.AjaxMFlow.Wai.Response MFlow.WaiMFlow.Forms.XHtmlMFlow.Wai.XHtml.AllWorkflow-0.7.0.4Control.WorkflowWorkflowbaseControl.Applicative<*<*><|> Data.Functor<$>Cookiectype cookieuser getCookies cookieHeaders urlDecodeAttribs ToHttpData toHttpDataTokentwfnametusertindqqr Processablepwfnamepuserpind getParamsParamsProcListHttpDataError anonymousnoScriptaddTokenToListdeleteTokenInListsend sendFlush sendFragmentsendEndFragmentreceiveflushRec receiveReqreceiveReqTimeout stateless transientaddMessageFlowsgetMessageFlows msgSchedulerhlogsetNotFoundResponsegetNotFoundResponsebtagbhtmlbbody MFlowState FormInputinred fromStringflinkflink1finput ftextareafselectfoptionfoption1 formAction addAttributes ToByteString toByteStringFormLetdigestViewFlowMUseruserName userRegister userValidate setAdminUser getAdminNamebreturn cachedWidgetrunFlowstepvalidatewactionwmodify getString getIntegergetInt getPasswordgetRadioActivegetRadio getCheckBox getTextBox getNewNamegetCurrentNamegetMultilineTextgetBool getSelect setOptionsetSelectedOption<<< normalize<++++>**><**ask goingBackclearEnvwform resetButton submitButtonwlinkwconcat|*>|+|flatten.<<..<+>..|*>..|+|..**>..<**..<|>..<++..++>. adminLoop addAdminWF setFilesPathaddFileServerWFlinkFile ajaxCommandajaxHeadTRespTRespRTRempty ToResponse toResponsectype1mkParamsmkparamwaiMessageFlow showCookie splitCookiesreadEnv urlEncodedextrasafe hexadecimalRespEndFragmFragmReq iorefqmapgetTokenfromReq delMsgHistory _messageFlowstellToWF logFileNamedefNotFoundResponsenotFoundResponse$fToHttpData[]$fSerializableToken $fReadToken $fShowToken$fIndexableToken$fProcessableReq$fMonoidHttpData$fToHttpDataByteString$fToHttpDataHttpData keyUserNamebytestring-0.10.0.0Data.ByteString.Lazyappendmix*>Tuple6Tuple5Tuple4Tuple3Tuple2Flattendoflat PasswdStrUserStr mfSequencemfCachedprevSeqonInit validatedmfLangmfEnvneedFormhasFormmfToken mfkillTime mfSessionTime mfCookiesmfHeadermfDebugLangOnClickCheckedValueTypeNameMFOptionrunViewFormElmWStateBackTrunBackTFailBackGoBackNoBack BackPointConfig upasswordeUsererror1 userPrefix keyConfigrconf iCanFailBack repeatPlease noFailBack liftBackT getParam1getEnvgetParam setOption1 stdHeader mFlowState0 getWFNamevalidreceiveWithTimeouts$fFormInputByteString$fFlattenMaybe(,,,,,)$fFlattenMaybe(,,,,)$fFlattenMaybe(,,,)$fFlattenMaybe(,,)$fFlattenMaybe(,)$fToByteStringByteString $fToHttpDataa$fFormLet(,,)mview$fFormLet(,)mview $fMonadIOView$fMonadStateMFlowStateView$fMonadTransView $fMonadView$fAlternativeView$fApplicativeView $fFunctorView$fFunctorFormElm$fSerialize(,)$fMonadStatesBackT$fMonadTransBackT$fFunctorBackT$fMonadIOBackT $fMonadBackT$fSerializeFailBack$fIndexableConfig$fIndexableUser$fSerializablea$fTypeableHtml$fFormInputHtml$fToByteStringHtml$fADDATTRSViewTCache-0.10.0.2 Data.TCache syncCache ssyncCache adminLoop1 adminMFlowerrorsusers showFormList optionsUser rfilesPathpathPrm fileServe directory directory1xhtml-3000.2.1Text.XHtml.Strict.Elementsheader$fToResponseHttpData$fToResponse[]$fToResponseByteString$fToResponseResponse$fToResponseTResp $fMonoidTResp splitPathghc-primGHC.PrimseqFlowflowrflownewFlow tvresourcesstatCookieNameputStateCookiegetStateCookie$fIndexableFlow$fSerializableFlow$fProcessableRequest Applicative safeIOToSTM setConditions defaultCheckclearSyncCacheatomicallySync syncWriteclearSyncCacheProcdeleteResourcesdeleteResource getResources getResource withResources withResourcewithSTMResourcesflushAll flushDBRef onNothingdelDBRefnewDBRefgetDBRef keyObjDBRef writeDBRef readDBRefnumElemsnewCachesetCacheCache Synchronous cacheSizecheck frecuency Asyncronous SyncManualSyncModeData.TCache.Triggers addTriggerData.TCache.DefsDBRefData.TCache.IResource resources delResource writeResource readResourcereadResourceByKey keyResource IResourceRetrytoReturntoDeletetoAdd Resources GHC.Conc.SyncSTM unsafeIOToSTM atomicallyoptionalliftA3liftA2liftA<**>puremanysomeempty AlternativegetConstConst unwrapMonad WrapMonad WrappedMonad unwrapArrow WrapArrow WrappedArrow getZipListZipListGHC.Base<$network-conduit-0.5.0.1Data.Conduit.Network.UtilsHostAnyHostIPv4HostIPv6HostHostPreference wai-1.3.0 Network.Wai responseLBSresponseSourceresponseStatusvault requestBody queryStringpathInfo remoteHostisSecurerequestHeaders serverPort serverNamerawQueryString rawPathInfo httpVersion requestMethodRequest ResponseFileResponseBuilderResponseSourceResponsefilePartByteCountfilePartOffsetFilePart Application Middleware warp-1.3.1Network.Wai.Handler.Warp.RunrunSettingsConnectionrunSettingsSocket runSettingsrunsocketConnection Network.Wai.Handler.Warp.Request parseRequest!Network.Wai.Handler.Warp.Response sendResponse!Network.Wai.Handler.Warp.SettingsdefaultSettingssettingsManagersettingsInterceptsettingsTimeoutsettingsOnClosesettingsOnOpensettingsOnException settingsHost settingsPortSettingsNetwork.Wai.Handler.Warp.TypesPortNotEnoughLines BadFirstLineNonHttpIncompleteHeadersConnectionClosedByPeerOverLargeHeaderInvalidRequestconnRecv connClose connSendFile connSendAll connSendMany Connection Network.Wai.Handler.Warp.Timeout withManagercancelresumepauseregisterKillThreadregister initializeManagerHandleText.XHtml.Strict prettyHtmlrenderHtmlWithLanguage renderHtmlshowHtmldocTypeText.XHtml.Extrasguimenuclickmapafile textfieldpasswordsubmitresetradiohiddencheckboxdefList unordListordListhotlinkpbullet spaceHtml copyright primHtmlChar linesToHtml lineToHtml stringToHtmlURLhotLinkAttributeshotLinkContents hotLinkURLHotLinkvariableulisttttrthetitlethespanthemapthelinkthehtmlthedivthecodethebasetheadthtfoottextareatdtbodytablesupsubstylestrongsmallselectscriptsamplequotepreparam paragraphoptionoptgroupolistobjectnoscriptmetalilegendlabelkeyboarditalicsinsinputimagehrh6h5h4h3h2h1formfieldset emphasizedtermdlistdeldefineddefcolgroupcolcitecaptionbrbuttonboldbody blockquotebigbdoareaanchoraddressacronymabbrText.XHtml.Strict.Attributeswidthvaluevalignusemaptitlethetypethestylethefortheclasssrcsizeshapeselectedrulesrowspanrowsrevrelnohrefnamemultiplemethod maxlengthlangismap identifier httpequivhreflanghrefheightenctypedisabledcoordscontentcolspancolscodebasechecked cellspacing cellpadding bordercolorborderarchivealtcodealtalignactionText.XHtml.InternalsprettyHtmlFragmentrenderHtmlFragmentshowHtmlFragmentprimHtmlstringToHtmlStringhtmlAttrstrAttrintAttr emptyAttritagtagisNoHtmlnoHtml+++ concatHtml<< htmlAttrPairHtmlAttrHtmltoHtmlFromListtoHtmlHTML!ADDATTRS changeAttrs CHANGEATTRS