:Class MiPage : #.HtmlPage

    ⍝∇:require =\HtmlPage.dyalog
    ⍝∇:require =\JSON.dyalog

    :Field Public _PageName←'' ⍝ Page file name
    :Field Public _PageDate←'' ⍝ Page saved date
    :field Public _Request     ⍝ HTTPRequest
    :field Public _Scripts←''
    :field Public _Styles←''
    :field public _Serialized←1 ⍝ serialized forms to return in _PageData
    :field Public _event        ⍝ set by APLJAX callback - event that was triggered
    :field Public _what         ⍝ set by APLJAX callback - name or id of the triggering element
    :field Public _value        ⍝ set by APLJAX callback - value of the triggering element
    :field Public _selector     ⍝ set by APLJAX callback - CSS/jQuery selector for the element that triggered the event
    :field Public _callback     ⍝ set by APLJAX callback - name of the callback function
    :field public _PageData
    :field public _AjaxResponse←''
    :field public _DebugCallbacks←0
    :field public OnLoad←''     ⍝ page equivalent to ⎕LX
    :field public shared _true←#.JSON.true     ⍝ same definition as in #.JSON
    :field public shared _false←#.JSON.false   ⍝ same definition as in #.JSON

    _used←'' ⍝ keep track of what's been used

    ∇ Make
      :Access public
      :Implements constructor :Base
      MakeCommon
    ∇

    ∇ Make1 req
      :Access public
      _Request←req
      :Implements constructor :base
      MakeCommon
    ∇

    ∇ MakeCommon
      _PageData←⎕NS''
    ∇

    ∇ {r}←Render;b
      :Access public
      :If ''≢OnLoad
          Use'JQuery'
      :EndIf
      b←RenderBody
      :If ~0∊⍴_Styles
          {(Head.Insert _html.link).Set(('href=',⍵)('rel' 'stylesheet')('type' 'text/css'))}¨∪⌽_Styles
      :EndIf
      :If ~0∊⍴_Scripts
          {(Head.Add _html.script).Set('src=',⍵)}¨∪_Scripts
      :EndIf
      :If ~0∊⍴Handlers
          b,←∊Handlers.Render
      :EndIf
      :If ''≢OnLoad
          b,←(⎕NEW #._html.script('$(function(){',OnLoad,'});')).Render
      :EndIf
      r←RenderPage b
      :If 0≠⎕NC⊂'_Request.Response'
          _Request.Response.HTML←r
      :EndIf
    ∇

    ∇ {r}←Wrap
      :Access public
      r←Render
    ∇

    ∇ Use resources;n;ind;t;x
      :Access public
      resources←eis resources
      :For x :In resources
          :If ~(⊂x)∊_used
              :Select ⊃x
              :Case '⍎' ⍝ script
                  _Scripts,←⊂1↓x
              :Case '⍕' ⍝ style sheet
                  _Styles,←⊂1↓x
              :Else
                  :If 0≠⎕NC⊂'_Request.Server.Config.Resources'
                  :AndIf ~0∊n←1↑⍴_Request.Server.Config.Resources
                      :If n≥ind←_Request.Server.Config.Resources[;1]⍳⊂x
                          :If ~0∊⍴t←{(~0∘∊∘⍴¨⍵)/⍵}(⊂ind 2)⊃_Request.Server.Config.Resources
                              _Scripts,←t
                          :EndIf
                          :If ~0∊⍴t←{(~0∘∊∘⍴¨⍵)/⍵}(⊂ind 3)⊃_Request.Server.Config.Resources
                              _Styles,←t
                          :EndIf
                      :Else
                          1 _Request.Server.Log _PageName,' references unknown resource: ',x
                      :EndIf
                  :EndIf
              :EndSelect
              _used,←⊂x
          :EndIf
      :EndFor
    ∇

    ∇ r←{proto}Get names
      :Access public
      proto←{6::⍵ ⋄ proto}''
      names←eis names
      names←,⍕names
      names←#.Strings.deb names
      :If ' '∊names
          names←{⎕ML←3 ⋄ ⍵⊂⍨⍵≠' '}names
          r←proto∘Get¨names
      :ElseIf 2≠_PageData.⎕NC names
          r←,proto
      :Else
          r←_PageData⍎names
          :If 2=≡r
              :If 1=⍴,r
                  r←#.JSON.toAPL⊃r
              :EndIf
          :EndIf
⍝          :If ~isChar proto
⍝              r←{0::⍵ ⋄ 0∊⍴⍵:⍬ ⋄ w←⍵ ⋄ ((w='-')/w)←'¯' ⋄ ⊃(//)⎕VFI w}r
⍝          :EndIf
      :EndIf
    ∇

    ∇ r←{proto}SessionGet names
      :Access public
      proto←{6::⍵ ⋄ proto}''
      names←,⍕names
      names←#.Strings.deb names
      :If ' '∊names
          names←{⎕ML←3 ⋄ ⍵⊂⍨⍵≠' '}names
          r←proto∘SessionGet¨names
      :ElseIf 2≠_Request.Session.⎕NC names
          r←proto
      :Else
          r←_Request.Session⍎names
          :If 1<|≡r ⋄ r←∊r ⋄ :EndIf
          :If ~0 2∊⍨10|⎕DR proto
              r←{0∊⍴⍵:⍬ ⋄ w←⍵ ⋄ ((w='-')/w)←'¯' ⋄ ⊃(//)⎕VFI w}r
          :EndIf
      :EndIf
    ∇

    ∇ Close session ⍝ Called when the session ends
      :Access Public Overridable
    ∇

    :section APLJax  ⍝ used for building APLJAX responses
    ∇ _resetAjax
      :Access public
      _AjaxResponse←''
    ∇

    ∇ r←_id
      :Access public
      ⍝ as there seems to be a problem with at least some Syncfusion widgets
      ⍝ being able to provide the id (or name) of the triggering element, we try to obtain it from _what or _selector
      r←''
      :Trap 0
          :If 0∊⍴r←_what
          :AndIf '#'=⊃_selector
              r←1↓_selector
          :EndIf
      :EndTrap
    ∇

    ∇ Respond arg
      :Access public
      ∘∘∘
    ∇

    ∇ r←renderContent content;c
      r←''
      content←eis content
      :While ~0∊⍴content
          :Select ≡c←⊃content
          :Case 0
              :If isClass c
                  :Select ⊃⍴content
                  :Case 1
                      r,←(⎕NEW c).Render
                  :Case 2
                      r,←(⎕NEW c(2⊃content)).Render
                  :Else
                      r,←(⎕NEW c(1↓content)).Render
                  :EndSelect
              :ElseIf isInstance c
                  r,←c.Render
              :Else
                  r,←(⎕NEW #.HtmlElement(''content)).Render
              :EndIf
              content←''
          :Case 1
              :If isClass⊃c
                  r,←(⎕NEW(⊃c)(1↓c)).Render
              :ElseIf isInstance⊃c
                  ∘∘∘ ⍝ should not happen! (I think)
              :Else
                  r,←(⎕NEW #.HtmlElement(''c)).Render
              :EndIf
              content←1↓content
          :Else
              r,←renderContent c
              content←1↓content
          :EndSelect
      :EndWhile
    ∇

    ∇ r←selector Replace content
      :Access public
      r←⊂('replace'selector)('data'(renderContent content))
    ∇
    ∇ r←selector Append content
      :Access public
      r←⊂('append'selector)('data'(renderContent content))
    ∇
    ∇ r←selector Prepend content
      :Access public
      r←⊂('prepend'selector)('data'(renderContent content))
    ∇
    ∇ r←Execute content
      :Access public
      r←⊂('execute'content)
    ∇

    ∇ r←name Assign data
      :Access public
      r←⊂('assign'name)('data'data)
    ∇

    :endsection

    :section Position
    ∇ ref Position args;inds;mask;parameters;my;at;of;collision;within;q
      :Access public shared
      ⍝ ref  - a reference to an instance of anything based on HtmlElement
      ⍝ args - position information per jQueryUI's Position widget http://api.jqueryui.com/position/
      ⍝        can be in any of the following forms
      ⍝      1) positional (my at of collision within)  N.B. we don't use the "using" parameter
      ⍝         example:  myDiv Position 'left top' 'right bottom' '#otherElement'
      ⍝                   positions myDiv's top left corner at the bottom right corner of the element with id "otherElement"
      ⍝      2) paired
      ⍝                   myDiv Position 'my' 'left top' 'at' 'right bottom' 'of' '#otherElement'
      ⍝                   myDiv Position ('my' 'left top') ('at' 'right bottom') ('of' '#otherElement')
      ⍝                   myDiv Position 3 2⍴'my' 'left top' 'at' 'right bottom' 'of' '#otherElement'
      ⍝ Note: positional arguments are in form horizontal (left center right) vertical (top center bottom)

      parameters←'my' 'at' 'of' 'collision' 'within'
      q←{1⌽'''''',{⍵/⍨1+''''=⍵}⍕⍵}
      :If isInstance ref
          :If 2=⍴⍴args ⍝ matrix
              args←,args
          :ElseIf 3=≡args
              args←⊃,/args
          :EndIf
          args←eis args
          inds←parameters⍳args
          :If ∨/mask←inds≤⍴parameters
              :If mask≡(2×+/mask)⍴1 0
                  parameters←mask/args
                  args←(1⌽mask)/args
              :EndIf
          :Else
              parameters←(⍴args)↑parameters
          :EndIf
          parameters(ref{⍺⍺⍎'Position.',⍺,'←',q ⍵})¨args
          ref.Uses,←⊂'JQueryUI'
          ref.Use
      :EndIf
    ∇
    :endsection

    :section Event Handling Support
    ∇ r←isPost
      :Access public
      r←{0::0 ⋄ _Request.isPost}⍬
    ∇

    ∇ r←isAPLJax
      :Access public
      r←{0::0 ⋄ _Request.isAPLJAX}⍬
    ∇

    ∇ r←sel Css args ⍝ JQuery css cover
      :Access public
      r←(sel #._JSS.JQuery'css')args
    ∇

    ∇ r←sel Val args ⍝ JQuery val cover
      :Access public
      r←(sel #._JSS.JQuery'val')args
    ∇

    ∇ r←sel Attr args ⍝ JQuery attr cover
      :Access public
      r←(sel #._JSS.JQuery'attr')args
    ∇

    ∇ r←sel RemoveAttr args ⍝ JQuery removeAttr cover
      :Access public
      r←(sel #._JSS.JQuery'removeAttr')args
    ∇

    ∇ r←sel Html args ⍝ JQuery html cover
      :Access public
      r←(sel #._JSS.JQuery'html')args
    ∇

    :endsection

    ∇ Debug;⎕TRAP
      :Access public
      ⎕TRAP←0⍴⎕TRAP
      ∘∘∘
    ∇

:EndClass

:Class MiPage : #.HtmlPage

    ⍝∇:require =\HtmlPage.dyalog
    ⍝∇:require =\JSON.dyalog

    :Field Public _PageName←'' ⍝ Page file name
    :Field Public _PageDate←'' ⍝ Page saved date
    :field Public _Request     ⍝ HTTPRequest
    :field Public _Scripts←''
    :field Public _Styles←''
    :field public _Serialized←1 ⍝ serialized forms to return in _PageData
    :field Public _event        ⍝ set by APLJAX callback - event that was triggered
    :field Public _what         ⍝ set by APLJAX callback - name or id of the triggering element
    :field Public _value        ⍝ set by APLJAX callback - value of the triggering element
    :field Public _selector     ⍝ set by APLJAX callback - CSS/jQuery selector for the element that triggered the event
    :field Public _callback     ⍝ set by APLJAX callback - name of the callback function
    :field public _PageData
    :field public _AjaxResponse←''
    :field public _DebugCallbacks←0
    :field public OnLoad←''     ⍝ page equivalent to ⎕LX
    :field public shared _true←#.JSON.true     ⍝ same definition as in #.JSON
    :field public shared _false←#.JSON.false   ⍝ same definition as in #.JSON

    _used←'' ⍝ keep track of what's been used

    ∇ Make
      :Access public
      :Implements constructor :Base
      MakeCommon
    ∇

    ∇ Make1 req
      :Access public
      _Request←req
      :Implements constructor :base
      MakeCommon
    ∇

    ∇ MakeCommon
      _PageData←⎕NS''
    ∇

    ∇ {r}←Render;b
      :Access public
      :If ''≢OnLoad
          Use'JQuery'
      :EndIf
      b←RenderBody
      :If ~0∊⍴_Styles
          {(Head.Insert _html.link).Set(('href=',⍵)('rel' 'stylesheet')('type' 'text/css'))}¨∪⌽_Styles
      :EndIf
      :If ~0∊⍴_Scripts
          {(Head.Add _html.script).Set('src=',⍵)}¨∪_Scripts
      :EndIf
      :If ~0∊⍴Handlers
          b,←∊Handlers.Render
      :EndIf
      :If ''≢OnLoad
          b,←(⎕NEW #._html.script('$(function(){',OnLoad,'});')).Render
      :EndIf
      r←RenderPage b
      :If 0≠⎕NC⊂'_Request.Response'
          _Request.Response.HTML←r
      :EndIf
    ∇

    ∇ {r}←Wrap
      :Access public
      r←Render
    ∇

    ∇ Use resources;n;ind;t;x
      :Access public
      resources←eis resources
      :For x :In resources
          :If ~(⊂x)∊_used
              :Select ⊃x
              :Case '⍎' ⍝ script
                  _Scripts,←⊂1↓x
              :Case '⍕' ⍝ style sheet
                  _Styles,←⊂1↓x
              :Else
                  :If 0≠⎕NC⊂'_Request.Server.Config.Resources'
                  :AndIf ~0∊n←1↑⍴_Request.Server.Config.Resources
                      :If n≥ind←_Request.Server.Config.Resources[;1]⍳⊂x
                          :If ~0∊⍴t←{(~0∘∊∘⍴¨⍵)/⍵}(⊂ind 2)⊃_Request.Server.Config.Resources
                              _Scripts,←t
                          :EndIf
                          :If ~0∊⍴t←{(~0∘∊∘⍴¨⍵)/⍵}(⊂ind 3)⊃_Request.Server.Config.Resources
                              _Styles,←t
                          :EndIf
                      :Else
                          1 _Request.Server.Log _PageName,' references unknown resource: ',x
                      :EndIf
                  :EndIf
              :EndSelect
              _used,←⊂x
          :EndIf
      :EndFor
    ∇

    ∇ r←{proto}Get names
      :Access public
      proto←{6::⍵ ⋄ proto}''
      names←eis names
      names←,⍕names
      names←#.Strings.deb names
      :If ' '∊names
          names←{⎕ML←3 ⋄ ⍵⊂⍨⍵≠' '}names
          r←proto∘Get¨names
      :ElseIf 2≠_PageData.⎕NC names
          r←,proto
      :Else
          r←_PageData⍎names
          :If 2=≡r
              :If 1=⍴,r
                  r←#.JSON.toAPL⊃r
              :EndIf
          :EndIf
⍝          :If ~isChar proto
⍝              r←{0::⍵ ⋄ 0∊⍴⍵:⍬ ⋄ w←⍵ ⋄ ((w='-')/w)←'¯' ⋄ ⊃(//)⎕VFI w}r
⍝          :EndIf
      :EndIf
    ∇

    ∇ r←{proto}GetRaw names
      :Access public
      proto←{6::⍵ ⋄ proto}''
      names←eis names
      names←,⍕names
      names←#.Strings.deb names
      :If ' '∊names
          names←{⎕ML←3 ⋄ ⍵⊂⍨⍵≠' '}names
          r←proto∘Get¨names
      :ElseIf 2≠_PageData.⎕NC names
          r←,proto
      :Else
          r←_PageData⍎names
          :If 2=≡r
              :If 1=⍴,r
                  r←⊃r
              :EndIf
          :EndIf
          :If ~isChar proto
              r←{0::⍵ ⋄ 0∊⍴⍵:⍬ ⋄ w←⍵ ⋄ ((w='-')/w)←'¯' ⋄ ⊃(//)⎕VFI w}r
          :EndIf
      :EndIf
    ∇

    ∇ r←{proto}SessionGet names
      :Access public
      proto←{6::⍵ ⋄ proto}''
      names←,⍕names
      names←#.Strings.deb names
      :If ' '∊names
          names←{⎕ML←3 ⋄ ⍵⊂⍨⍵≠' '}names
          r←proto∘SessionGet¨names
      :ElseIf 2≠_Request.Session.⎕NC names
          r←proto
      :Else
          r←_Request.Session⍎names
          :If 1<|≡r ⋄ r←∊r ⋄ :EndIf
          :If ~0 2∊⍨10|⎕DR proto
              r←{0∊⍴⍵:⍬ ⋄ w←⍵ ⋄ ((w='-')/w)←'¯' ⋄ ⊃(//)⎕VFI w}r
          :EndIf
      :EndIf
    ∇

    ∇ Close session ⍝ Called when the session ends
      :Access Public Overridable
    ∇

    :section APLJax  ⍝ used for building APLJAX responses
    ∇ _resetAjax
      :Access public
      _AjaxResponse←''
    ∇

    ∇ r←_id
      :Access public
      ⍝ as there seems to be a problem with at least some Syncfusion widgets
      ⍝ being able to provide the id (or name) of the triggering element, we try to obtain it from _what or _selector
      r←''
      :Trap 0
          :If 0∊⍴r←_what
          :AndIf '#'=⊃_selector
              r←1↓_selector
          :EndIf
      :EndTrap
    ∇

    ∇ Respond arg
      :Access public
      ∘∘∘
    ∇

    ∇ r←renderContent content;c
      r←''
      content←eis content
      :While ~0∊⍴content
          :Select ≡c←⊃content
          :Case 0
              :If isClass c
                  :Select ⊃⍴content
                  :Case 1
                      r,←(⎕NEW c).Render
                  :Case 2
                      r,←(⎕NEW c(2⊃content)).Render
                  :Else
                      r,←(⎕NEW c(1↓content)).Render
                  :EndSelect
              :ElseIf isInstance c
                  r,←c.Render
              :Else
                  r,←(⎕NEW #.HtmlElement(''content)).Render
              :EndIf
              content←''
          :Case 1
              :If isClass⊃c
                  r,←(⎕NEW(⊃c)(1↓c)).Render
              :ElseIf isInstance⊃c
                  ∘∘∘ ⍝ should not happen! (I think)
              :Else
                  r,←(⎕NEW #.HtmlElement(''c)).Render
              :EndIf
              content←1↓content
          :Else
              r,←renderContent c
              content←1↓content
          :EndSelect
      :EndWhile
    ∇

    ∇ r←selector Replace content
      :Access public
      r←⊂('replace'selector)('data'(renderContent content))
    ∇
    ∇ r←selector Append content
      :Access public
      r←⊂('append'selector)('data'(renderContent content))
    ∇
    ∇ r←selector Prepend content
      :Access public
      r←⊂('prepend'selector)('data'(renderContent content))
    ∇
    ∇ r←Execute content
      :Access public
      r←⊂('execute'content)
    ∇

    ∇ r←name Assign data
      :Access public
      r←⊂('assign'name)('data'data)
    ∇

    :endsection

    :section Position
    ∇ ref Position args;inds;mask;parameters;my;at;of;collision;within;q
      :Access public shared
      ⍝ ref  - a reference to an instance of anything based on HtmlElement
      ⍝ args - position information per jQueryUI's Position widget http://api.jqueryui.com/position/
      ⍝        can be in any of the following forms
      ⍝      1) positional (my at of collision within)  N.B. we don't use the "using" parameter
      ⍝         example:  myDiv Position 'left top' 'right bottom' '#otherElement'
      ⍝                   positions myDiv's top left corner at the bottom right corner of the element with id "otherElement"
      ⍝      2) paired
      ⍝                   myDiv Position 'my' 'left top' 'at' 'right bottom' 'of' '#otherElement'
      ⍝                   myDiv Position ('my' 'left top') ('at' 'right bottom') ('of' '#otherElement')
      ⍝                   myDiv Position 3 2⍴'my' 'left top' 'at' 'right bottom' 'of' '#otherElement'
      ⍝ Note: positional arguments are in form horizontal (left center right) vertical (top center bottom)

      parameters←'my' 'at' 'of' 'collision' 'within'
      q←{1⌽'''''',{⍵/⍨1+''''=⍵}⍕⍵}
      :If isInstance ref
          :If 2=⍴⍴args ⍝ matrix
              args←,args
          :ElseIf 3=≡args
              args←⊃,/args
          :EndIf
          args←eis args
          inds←parameters⍳args
          :If ∨/mask←inds≤⍴parameters
              :If mask≡(2×+/mask)⍴1 0
                  parameters←mask/args
                  args←(1⌽mask)/args
              :EndIf
          :Else
              parameters←(⍴args)↑parameters
          :EndIf
          parameters(ref{⍺⍺⍎'Position.',⍺,'←',q ⍵})¨args
          ref.Uses,←⊂'JQueryUI'
          ref.Use
      :EndIf
    ∇
    :endsection

    :section Event Handling Support
    ∇ r←isPost
      :Access public
      r←{0::0 ⋄ _Request.isPost}⍬
    ∇

    ∇ r←isAPLJax
      :Access public
      r←{0::0 ⋄ _Request.isAPLJAX}⍬
    ∇

    ∇ r←sel Css args ⍝ JQuery css cover
      :Access public
      r←(sel #._JSS.JQuery'css')args
    ∇

    ∇ r←sel Val args ⍝ JQuery val cover
      :Access public
      r←(sel #._JSS.JQuery'val')args
    ∇

    ∇ r←sel Attr args ⍝ JQuery attr cover
      :Access public
      r←(sel #._JSS.JQuery'attr')args
    ∇

    ∇ r←sel RemoveAttr args ⍝ JQuery removeAttr cover
      :Access public
      r←(sel #._JSS.JQuery'removeAttr')args
    ∇

    ∇ r←sel Html args ⍝ JQuery html cover
      :Access public
      r←(sel #._JSS.JQuery'html')args
    ∇

    :endsection

    ∇ Debug;⎕TRAP
      :Access public
      ⎕TRAP←0⍴⎕TRAP
      ∘∘∘
    ∇

:EndClass

Add MiPage.GetRaw

Add MiPage.GetRaw


:Class MS3Server : MiServer
⍝ This is an example of a customized MiServer
⍝ The MiServer class exposes several overridable methods that can be customized by the user
⍝ In this case we customize the onServerLoad method
⍝ The ClassName parameter in the Server.xml configuration file is used to specify the customized class

    :Include #.MS3SiteUtils ⍝∇:require =/MS3SiteUtils

    ∇ Make config
      :Access Public
      :Implements Constructor :Base config
     ⍝ Version warning
      :If 14>{⊃(//)⎕VFI ⍵/⍨2>+\'.'=⍵}2⊃'.'⎕WG'APLVersion'
          ⎕←''
          ⎕←'MiServer 3.0 itself will run under Dyalog APL versions 13.2 and later'
          ⎕←'However, the MS3 MiSite uses features found only in Dyalog APL versions beginning with 14.0'
          ⎕←''
          ⎕←'Please restart the MS3 MiSite using Dyalog APL version 14.0 or later...'
          →
      :EndIf
    ∇

    ∇ onServerLoad
      :Access Public Override
    ⍝ Handle any server startup processing
      {}C ⍝ initialize CACHE
    ∇

:EndClass

:Class MS3Server : MiServer
⍝ This is an example of a customized MiServer
⍝ The MiServer class exposes several overridable methods that can be customized by the user
⍝ In this case we customize the onServerLoad method
⍝ The ClassName parameter in the Server.xml configuration file is used to specify the customized class

    :Include #.MS3SiteUtils ⍝∇:require =/MS3SiteUtils

    ∇ Make config
      :Access Public
      :Implements Constructor :Base config
     ⍝ Version warning
      :If 14>{⊃(//)⎕VFI ⍵/⍨2>+\'.'=⍵}2⊃'.'⎕WG'APLVersion'
          ⎕←''
          ⎕←'MiServer 3.0 itself will run under Dyalog APL versions 13.2 and later'
          ⎕←'However, the MS3 MiSite uses features found only in Dyalog APL versions beginning with 14.0'
          ⎕←'From version 15.0, Dyalog APL is available free of charge at http://www.dyalog.com'
          ⎕←''
          ⎕←'Please restart the MS3 MiSite using Dyalog APL version 14.0 or later...'
          →
      :EndIf
    ∇

    ∇ onServerLoad
      :Access Public Override
    ⍝ Handle any server startup processing
      {}C ⍝ initialize CACHE
    ∇

:EndClass

Upgrade message inculdes note of 15.0+ being free.


:class aSimple : MiPageSample
⍝ Control:: _html.a
⍝ Description:: Insert a hyperlink

    ∇ Compose
      :Access public
      Add 'Click '
      'href' 'http://www.dyalog.com/meet-team-dyalog.htm'Add _.a'here'
      Add ' to meet us.'
    ∇

:endclass

:class aSimple : MiPageSample
⍝ Control:: _html.a
⍝ Description:: Insert a hyperlink

    ∇ Compose
      :Access public
      Add'Click '
      'href=http://www.dyalog.com/meet-team-dyalog.htm'Add _.a'here'
      Add' to meet us.'
    ∇

:endclass

Fix to new ParseAttr syntax

Fix to new ParseAttr syntax


#!/usr/local/bin/apl -s

'Day 3: Perfectly Spherical Houses in a Vacuum'

i ← (0 0)
cmds ← ('<' '>' '^' 'v')
dirs ← ((¯1 0) (1 0) (0 ¯1) (0 1))
houses ← ∪ (0 0) , i { ++\⍵ } { dirs[ti] ⊣ ti ← cmds ⍳ ⍵ } ⍞
⍴ houses ⍝ the amount of houses to visit

)OFF

#!/usr/local/bin/apl -s

'Day 3: Perfectly Spherical Houses in a Vacuum'

cmds ← ('<' '>' '^' 'v')
dirs ← ((¯1 0) (1 0) (0 ¯1) (0 1))
houses ← ∪ (0 0) , { ++\⍵ } { dirs[ti] ⊣ ti ← cmds ⍳ ⍵ } ⍞
⍴ houses ⍝ the amount of houses to visit

)OFF

Trim fat on apl nr 1

Trim fat on apl nr 1


:Namespace Strings

    (⎕IO ⎕ML)←1

    lower←'abcdefghijklmnopqrstuvwxyzáâãçèêëìíîïðòóôõùúûýàäåæéñöøü'
    upper←'ABCDEFGHIJKLMNOPQRSTUVWXYZÁÂÃÇÈÊËÌÍÎÏÐÒÓÔÕÙÚÛÝÀÄÅÆÉÑÖØÜ'

    ∇ r←lc r;m
      m←r∊upper
      (m/r)←lower[upper⍳m/r]
    ∇

    ∇ r←uc r;m
      m←r∊lower
      (m/r)←upper[lower⍳m/r]
    ∇

    vtom←{⎕ML←3 ⋄ ⍺←' ' ⋄ ⊃⍵⊂⍨~⍵∊⍺} ⍝ vector to matrix

    ∇ r←dlb x
    ⍝ Delete Leading Blanks
      r←(+/∧\' '=x)↓x
    ∇

    ∇ r←dtb x
    ⍝ Delete Trailing Blanks
      r←(-+/∧\' '=⌽x)↓x
    ∇

    ∇ r←deb x
    ⍝ Delete extraneous blanks
      r←{1↓¯1↓(~'  '⍷⍵)/⍵}' ',x,' '
    ∇

    ∇ r←dmb x;m
    ⍝ Delete multiple blanks
      r←(m⍲1⌽m←' '=x)/x
    ∇

    ∇ str←str subst(from to);m;⎕IO;i
    ⍝ simple string substitution
      ⎕IO←0
      :Trap 0
          str←((esc from)⎕R(esc to))str
      :Else
          →(∨/m←from⍷str)↓0
          i←m⍳1
          str←((i↑str),to,(i+⍴from)↓str)subst(from to)
      :EndTrap
    ∇

    esc←{m←∊(-1+⍵∊'%\')↑¨1 ⋄ r←m\⍵ ⋄ ((~m)/r)←'\' ⋄ r }

    scaledFmt←{0=⍵:' 0' ⋄ ⍵{((1+⍵)⊃(⊂''),'KMGTQP'),⍨(1⌊⍵)⍕⍺÷10*3×⍵}⌊3÷⍨10⍟⍵}

    tonum←{0∊⍴⍵:⍬ ⋄ w←⍵ ⋄ ((w='-')/w)←'¯'⋄2 1⊃⎕VFI w}

    ∇ r←{d}commaFmt n
      :If 0=⎕NC'd'
          r←(,¨'CI20'∘⎕FMT¨n)~¨' '
      :Else
          r←(,¨('CF20.',⍕d)∘⎕FMT¨n)~¨' '
      :EndIf
    ∇

    beginsWith←{(,⍺){⍵≡(⍴⍵)↑⍺},⍵}
    endsWith←{(,⍺){⍵≡(-⍴⍵)↑⍺},⍵}

:EndNamespace

:Namespace Strings

    (⎕IO ⎕ML)←1

    lower←'abcdefghijklmnopqrstuvwxyzáâãçèêëìíîïðòóôõùúûýàäåæéñöøü'
    upper←'ABCDEFGHIJKLMNOPQRSTUVWXYZÁÂÃÇÈÊËÌÍÎÏÐÒÓÔÕÙÚÛÝÀÄÅÆÉÑÖØÜ'

    ∇ r←lc r;m
      m←r∊upper
      (m/r)←lower[upper⍳m/r]
    ∇

    ∇ r←uc r;m
      m←r∊lower
      (m/r)←upper[lower⍳m/r]
    ∇

    vtom←{⎕ML←3 ⋄ ⍺←' ' ⋄ ⊃⍵⊂⍨~⍵∊⍺} ⍝ vector to matrix

    ∇ r←dlb x
    ⍝ Delete Leading Blanks
      r←(+/∧\' '=x)↓x
    ∇

    ∇ r←dtb x
    ⍝ Delete Trailing Blanks
      r←(-+/∧\' '=⌽x)↓x
    ∇

    ∇ r←deb x
    ⍝ Delete extraneous blanks
      r←{1↓¯1↓(~'  '⍷⍵)/⍵}' ',x,' '
    ∇

    ∇ r←dmb x;m
    ⍝ Delete multiple blanks
      r←(m⍲1⌽m←' '=x)/x
    ∇

    ∇ str←str subst(from to);m;⎕IO;i
    ⍝ simple string substitution
      ⎕IO←0
      :Trap 0
          str←((esc from)⎕R(esc to))str
      :Else
          →(∨/m←from⍷str)↓0
          i←m⍳1
          str←((i↑str),to,(i+⍴from)↓str)subst(from to)
      :EndTrap
    ∇

    esc←{m←∊(-1+⍵∊'%\')↑¨1 ⋄ r←m\⍵ ⋄ ((~m)/r)←'\' ⋄ r }

    scaledFmt←{0=⍵:' 0' ⋄ ⍵{((1+⍵)⊃(⊂''),'KMGTQP'),⍨(1⌊⍵)⍕⍺÷10*3×⍵}⌊3÷⍨10⍟⍵}

    tonum←{0∊⍴⍵:⍬ ⋄ w←⍵ ⋄ ((w='-')/w)←'¯'⋄2 1⊃⎕VFI w}

    ∇ r←{d}commaFmt n
      :If 0=⎕NC'd'
          r←(,¨'CI20'∘⎕FMT¨n)~¨' '
      :Else
          r←(,¨('CF20.',⍕d)∘⎕FMT¨n)~¨' '
      :EndIf
      (∊r)←{w←⍵ ⋄ w⊣((w='¯')/w)←'-'}∊r
    ∇

    beginsWith←{(,⍺){⍵≡(⍴⍵)↑⍺},⍵}
    endsWith←{(,⍺){⍵≡(-⍴⍵)↑⍺},⍵}

:EndNamespace

replace high minus by low

strings.commaFmt: replace high minus by low


Revert "rm "0=⍴⍴⍵:"; the joys of being dimension-agnostic"

This reverts commit c7ece6626849698c9480e23228bb2f48cd945f15.

issue #67


:Class Menuexample3 : MiPageSample
⍝ Demonstrate the SyncFusion ejMenu widget

    ⎕ml←⎕io←1

    ∇ r←Render;items;t;tmp;a;i;m;opt
      :Access Public
⍝      tmp←⎕XML∊example
⍝      i←a/⍳⍴a←tmp[;2]∊⊂,'a' ⋄ tmp[i-1;3]←tmp[i;3] ⋄ tmp←(~a)⌿tmp
⍝      items←↓⍉tmp[;1 3],⊂''
      Add build
      m←Add _SF.ejMenu
      opt←'{dataSource: data, id: "id", parentId: "parentId", text: "text", spriteCssClass: "sprite"}'
      'fields'm.Option opt
⍝      'datasource'm.Option'data'
 ⍝     'id'm.Option'id'
  ⍝    'parentid'm.Option'parentId'
   ⍝   'text'm.Option'text'
    ⍝  'spriteCssClass'm.Option'sprite'
     ⍝ Add m
    ∇

    ∇ m←build;P;F;C;cr
    ⍝ This data recreates SuncFusion's http://js.syncfusion.com/demos/web/#!/azure/menu/databinding-localdata page example
⍝[{id:1,parentid:null,text:"Group A"}
⍝,{id:2,parentid:null,text:"Group B"}
⍝,{id:3,parentid:null,text:"Group C"}
⍝,{id:4,parentid:null,text:"Group D"}
⍝,{id:5,parentid:null,text:"Group E"}
⍝,{id:11,parentId:1,sprite:"flag-dz",text:"Algeria"}
⍝,{id:12,parentId:1,sprite:"flag-am",text:"Armenia"}
⍝,{id:13,parentId:1,sprite:"flag-bd",text:"Bangladesh"}
⍝,{id:14,parentId:1,sprite:"flag-cu",text:"Cuba"}
⍝,{id:15,parentId:2,sprite:"flag-dk",text:"Denmark"}
⍝,{id:16,parentId:2,sprite:"flag-eg",text:"Egypt"}
⍝,{id:17,parentId:3,sprite:"flag-fi",text:"Finland"}
⍝,{id:18,parentId:3,sprite:"flag-in",text:"India"}
⍝,{id:19,parentId:3,sprite:"flag-my",text:"Malaysia"}
⍝,{id:20,parentId:4,sprite:"flag-nz",text:"New Zealand"}
⍝,{id:21,parentId:4,sprite:"flag-no",text:"Norway"}
⍝,{id:22,parentId:4,sprite:"flag-pl",text:"Poland"}
⍝,{id:23,parentId:5,sprite:"flag-ro",text:"Romania"}
⍝,{id:24,parentId:5,sprite:"flag-sg",text:"Singapore"}
⍝,{id:25,parentId:5,sprite:"flag-th",text:"Thailand"}
⍝,{id:26,parentId:5,sprite:"flag-ua",text:"Ukraine"}
⍝,{id:111,parentId:11,text:"First Place"}
⍝,{id:112,parentId:12,text:"Second Place"}
⍝,{id:113,parentId:13,text:"Third Place"}
⍝,{id:114,parentId:14,text:"Fourth Place"}
⍝,{id:115,parentId:15,text:"First Place"}
⍝,{id:116,parentId:16,text:"Second Place"}
⍝,{id:117,parentId:17,text:"Third Place"}
⍝,{id:118,parentId:18,text:"First Place"}
⍝,{id:119,parentId:19,text:"Second Place"}
⍝,{id:120,parentId:20,text:"First Place"}
⍝,{id:121,parentId:21,text:"Second Place"}
⍝,{id:122,parentId:22,text:"Third Place"}
⍝,{id:123,parentId:23,text:"Fourth Place"}
⍝,{id:124,parentId:24,text:"First Place"}
⍝,{id:125,parentId:25,text:"Second Place"}
⍝,{id:126,parentId:26,text:"Third Place"}]

      m←{'{id:',(⍕⍵),',text:"Group ',⎕A[⍵],'",parentid:null},'}¨⍳5
      C←'Algeria' 'Armenia' 'Bangladesh' 'Cuba' 'Denmark' 'Egypt' 'Finland' 'India'
      C,←'Malaysia' 'New Zealand' 'Norway' 'Poland' 'Romania' 'Singapore' 'Thailand' 'Ukraine'
      F←'flag-'∘,¨↓16 2⍴'dzambdcudkegfiinmynznoplrosgthua'
      m,←(4 2 3 3 4/⍳5){'{id:',(⍕10+⍵),',parentId:',(⍕⍺),',text:"',(⍵⊃C),'",sprite:"',(⍵⊃F),'"},'}¨⍳16
      P←'First' 'Second' 'Third' 'Fourth'[1 2 3 4 1 2 3 1 2 1 2 3 4 1 2 3],¨⊂' Place'
      m,←{'{id:',(⍕110+⍵),',parentId:',(⍕10+⍵),',text:"',(⍵⊃P),'"},'}¨⍳16
      m[⍴m]↓⍨←¯1
      m←m,¨cr←⎕UCS 13
      m←∊1⌽('];' '<script type="text/javascript">var data = [',¨cr),m
    ∇

:EndClass

:Class Menuexample3 : MiPageSample
⍝ Demonstrate the SyncFusion ejMenu widget

    ⎕ml←⎕io←1

    ∇ r←Render;items;t;tmp;a;i;m;opt
      :Access Public
⍝      tmp←⎕XML∊example
⍝      i←a/⍳⍴a←tmp[;2]∊⊂,'a' ⋄ tmp[i-1;3]←tmp[i;3] ⋄ tmp←(~a)⌿tmp
⍝      items←↓⍉tmp[;1 3],⊂''
      Add build
      m←Add _SF.ejMenu
      opt←'{dataSource: data, id: "id", parentId: "parentId", text: "text", spriteCssClass: "sprite"}'
      'fields'm.Option opt
⍝      'datasource'm.Option'data'
 ⍝     'id'm.Option'id'
  ⍝    'parentid'm.Option'parentId'
   ⍝   'text'm.Option'text'
    ⍝  'spriteCssClass'm.Option'sprite'
     ⍝ Add m
    ∇

    ∇ m←build;P;F;C;cr
    ⍝ This data recreates SuncFusion's http://js.syncfusion.com/demos/web/#!/azure/menu/databinding-localdata page example
⍝[{id:1,parentid:null,text:"Group A"}
⍝,{id:2,parentid:null,text:"Group B"}
⍝,{id:3,parentid:null,text:"Group C"}
⍝,{id:4,parentid:null,text:"Group D"}
⍝,{id:5,parentid:null,text:"Group E"}
⍝,{id:11,parentId:1,sprite:"flag-dz",text:"Algeria"}
⍝,{id:12,parentId:1,sprite:"flag-am",text:"Armenia"}
⍝,{id:13,parentId:1,sprite:"flag-bd",text:"Bangladesh"}
⍝,{id:14,parentId:1,sprite:"flag-cu",text:"Cuba"}
⍝,{id:15,parentId:2,sprite:"flag-dk",text:"Denmark"}
⍝,{id:16,parentId:2,sprite:"flag-eg",text:"Egypt"}
⍝,{id:17,parentId:3,sprite:"flag-fi",text:"Finland"}
⍝,{id:18,parentId:3,sprite:"flag-in",text:"India"}
⍝,{id:19,parentId:3,sprite:"flag-my",text:"Malaysia"}
⍝,{id:20,parentId:4,sprite:"flag-nz",text:"New Zealand"}
⍝,{id:21,parentId:4,sprite:"flag-no",text:"Norway"}
⍝,{id:22,parentId:4,sprite:"flag-pl",text:"Poland"}
⍝,{id:23,parentId:5,sprite:"flag-ro",text:"Romania"}
⍝,{id:24,parentId:5,sprite:"flag-sg",text:"Singapore"}
⍝,{id:25,parentId:5,sprite:"flag-th",text:"Thailand"}
⍝,{id:26,parentId:5,sprite:"flag-ua",text:"Ukraine"}
⍝,{id:111,parentId:11,text:"First Place"}
⍝,{id:112,parentId:12,text:"Second Place"}
⍝,{id:113,parentId:13,text:"Third Place"}
⍝,{id:114,parentId:14,text:"Fourth Place"}
⍝,{id:115,parentId:15,text:"First Place"}
⍝,{id:116,parentId:16,text:"Second Place"}
⍝,{id:117,parentId:17,text:"Third Place"}
⍝,{id:118,parentId:18,text:"First Place"}
⍝,{id:119,parentId:19,text:"Second Place"}
⍝,{id:120,parentId:20,text:"First Place"}
⍝,{id:121,parentId:21,text:"Second Place"}
⍝,{id:122,parentId:22,text:"Third Place"}
⍝,{id:123,parentId:23,text:"Fourth Place"}
⍝,{id:124,parentId:24,text:"First Place"}
⍝,{id:125,parentId:25,text:"Second Place"}
⍝,{id:126,parentId:26,text:"Third Place"}]

      m←{'{id:',(⍕⍵),',text:"Group ',⎕A[⍵],'",parentid:null},'}¨⍳5
      C←'Algeria' 'Armenia' 'Bangladesh' 'Cuba' 'Denmark' 'Egypt' 'Finland' 'India'
      C,←'Malaysia' 'New Zealand' 'Norway' 'Poland' 'Romania' 'Singapore' 'Thailand' 'Ukraine'
      F←'flag-'∘,¨↓16 2⍴'dzambdcudkegfiinmynznoplrosgthua'
      m,←(4 2 3 3 4/⍳5){'{id:',(⍕10+⍵),',parentId:',(⍕⍺),',text:"',(⍵⊃C),'",sprite:"',(⍵⊃F),'"},'}¨⍳16
      P←'First' 'Second' 'Third' 'Fourth'[1 2 3 4 1 2 3 1 2 1 2 3 4 1 2 3],¨⊂' Place'
      m,←{'{id:',(⍕110+⍵),',parentId:',(⍕10+⍵),',text:"',(⍵⊃P),'"},'}¨⍳16
      m[⍴m]↓⍨←¯1
      m←m,¨cr←⎕UCS 13
      m←∊2⌽('];' '</script>' '<script type="text/javascript">var data = [',¨cr),m
    ∇

:EndClass

complete script tag

complete script tag

tag was missing


:class Select : #._html.select
⍝ Description:: Dyalog Enhanced HTML select
⍝ Constructor:: [options [[selected] [prompt]]]
⍝ options   - vector of options or 2 column matrix of displayed[;1] and returned[;2] values
⍝ selected  - Boolean or integer array indicating pre-selected options(s)
⍝ prompt      - first item to display (has no value) (default '[Select]')
⍝ Public Fields::
⍝ Options   - vector of options or 2 column matrix of displayed[;1] and returned[;2] values
⍝ Selected  - Boolean or integer array indicating pre-selected options(s)
⍝ Prompt      - first item to display (has no value) (default '[Select]')
⍝ Examples::
⍝ Select  ('Choice 1' 'Choice 2' 'Choice 3')
⍝ Select  (3 2⍴'Choice 1' 'c1' 'Choice 2' 'c2' 'Choice 3' 'c3')
⍝ Select ((3 2⍴'Choice 1' 'c1' 'Choice 2' 'c2' 'Choice 3' 'c3') 2) ⍝ second item is selected
⍝ Select ((3 2⍴'Choice 1' 'c1' 'Choice 2' 'c2' 'Choice 3' 'c3') (0 1 0)) ⍝ second item is selected
⍝ Select ((3 2⍴'Choice 1' 'c1' 'Choice 2' 'c2' 'Choice 3' 'c3') 2 'Pick One')

    :field public Options←0 2⍴⊂''     ⍝ vector or matrix [;1] display, [;2] value
    :field public Selected←⍬          ⍝ either Boolean integer vector indicating
    :field public Prompt←'[Select]'   ⍝ character vector "Prompt" choice - the first choice on the list and does not have a value

    ∇ make
      :Access public
      :Implements constructor
    ∇

    ∇ make1 args;attr
      :Access public
      :Implements constructor
      args←eis args
      :If (|≡args)∊0 1 2
          args←,⊂args
      :EndIf
      (Options Selected Prompt)←args defaultArgs Options Selected Prompt
    ∇

    ∇ r←Render;opts
      :Access public
      Content←''
      SetId
      :If ~0∊⍴Options
          opts←eis Options
          :If 1=⍴⍴opts
              opts←opts,⍪opts
          :EndIf
          :If 11=⎕DR sel←Selected
              sel←{⍵/⍳⍴⍵},sel
          :EndIf
          opts[sel;1],⍨←⎕UCS 1
          Add Prompt FormatOptions opts
      :EndIf
      r←⎕BASE.Render
    ∇

    ∇ r←{Prompt}FormatOptions opts;opt
      :Access Public
      :If 0=⎕NC'Prompt' ⋄ Prompt←'' ⋄ :EndIf
      :If 1=⍴⍴opts ⋄ opts←opts,⍪opts ⋄ :EndIf
      opt←(0∊⍴Prompt)↓(Prompt'')⍪opts
      r←∊{sel←(⎕UCS 1)=1↑⍺ ⋄ '<option',(⍵ ine' value="',(HtmlSafeText ⍵),'"'),(sel/' selected="selected"'),'>',(⍕sel↓⍺),'</option>'}/opt

    ∇
:endclass

:class Select : #._html.select
⍝ Description:: Dyalog Enhanced HTML select
⍝ Constructor:: [options [[selected] [prompt]]]
⍝ options   - vector of options or 2 column matrix of displayed[;1] and returned[;2] values
⍝ selected  - Boolean or integer array indicating pre-selected options(s)
⍝ prompt      - first item to display (has no value) (default '[Select]')
⍝ Public Fields::
⍝ Options   - vector of options or 2 column matrix of displayed[;1] and returned[;2] values
⍝ Selected  - Boolean or integer array indicating pre-selected options(s)
⍝ Prompt      - first item to display (has no value) (default '[Select]')
⍝ Examples::
⍝ Select  ('Choice 1' 'Choice 2' 'Choice 3')
⍝ Select  (3 2⍴'Choice 1' 'c1' 'Choice 2' 'c2' 'Choice 3' 'c3')
⍝ Select ((3 2⍴'Choice 1' 'c1' 'Choice 2' 'c2' 'Choice 3' 'c3') 2) ⍝ second item is selected
⍝ Select ((3 2⍴'Choice 1' 'c1' 'Choice 2' 'c2' 'Choice 3' 'c3') (0 1 0)) ⍝ second item is selected
⍝ Select ((3 2⍴'Choice 1' 'c1' 'Choice 2' 'c2' 'Choice 3' 'c3') 2 'Pick One')

    :field public Options←0 2⍴⊂''     ⍝ vector or matrix [;1] display, [;2] value
    :field public Selected←⍬          ⍝ either Boolean integer vector indicating
    :field public Prompt←'[Select]'   ⍝ character vector "Prompt" choice - the first choice on the list and does not have a value

    ∇ make
      :Access public
      :Implements constructor
    ∇

    ∇ make1 args;attr
      :Access public
      :Implements constructor
      args←eis args
      :If (|≡args)∊0 1 2
          args←,⊂args
      :EndIf
      (Options Selected Prompt)←args defaultArgs Options Selected Prompt
    ∇

    ∇ r←Render;opts
      :Access public
      Content←''
      SetId
      :If ~0∊⍴Options
          opts←eis Options
          :If 1=⍴⍴opts
              opts←opts,⍪opts
          :EndIf
          :If 11=⎕DR sel←Selected
              sel←{⍵/⍳⍴⍵},sel
          :EndIf
          opts[sel;1],⍨←⎕UCS 1
          Add Prompt FormatOptions opts
      :EndIf
      r←⎕BASE.Render
    ∇

    ∇ r←{Prompt}FormatOptions opts;opt
      :Access Public Shared
      :If 0=⎕NC'Prompt' ⋄ Prompt←'' ⋄ :EndIf
      :If 1=⍴⍴opts ⋄ opts←opts,⍪opts ⋄ :EndIf
      opt←(0∊⍴Prompt)↓(Prompt'')⍪opts
      r←∊{sel←(⎕UCS 1)=1↑⍺ ⋄ '<option',(⍵ ine' value="',(HtmlSafeText ⍵),'"'),(sel/' selected="selected"'),'>',(⍕sel↓⍺),'</option>'}/opt

    ∇
:endclass

Make _DC.Select.FormatOptions Public Shared


 msg←Test dummy;fig
 fig←Find'fig'
 msg←(283 890≢fig.Size.(Height Width))/'figure size is not 283x890'

 msg←Test dummy;fig
 fig←Find'fig'
 msg←(~fig.Displayed∧0∧.≠fig.Size.(Height Width))/'figure not displayed'

Improve FigureSimple QA

Improve FigureSimple QA


:Class ejButtonSimple : MiPageSample
⍝ Control:: _SF.ejButton
⍝ Description::  two buttons, one en/disables the other and another that displays an alert

    ∇ Compose
      :Access Public

     ⍝ The first button (b1)
      b1←'b1'Add _SF.ejButton'Toggle its state →'
      'type'b1.Set'ej.ButtonType.Button'
      b1.On'click' 'myCallback'

     ⍝ The second button (b2)
      b2←Add _SF.ejButton'Show alert'
      b2.id←'b2'
      'type' 'enabled'b2.Set'ej.ButtonType.Button'_false
      b2.On'click' 'myCallback'
    ∇

    ∇ r←myCallback
      :Access public
      ∘∘∘∘
     ⍝ This callback simply flips b2's state when b1 is clicked
      :If 'b1'≡_what
          r←'enabled'b2.Update⊃_true _false~b2.GetOption'enabled'
      :Else
          r←Execute'alert("Hi there!")'
      :EndIf

    ∇

:EndClass

:Class ejButtonSimple : MiPageSample
⍝ Control:: _SF.ejButton
⍝ Description::  two buttons, one en/disables the other and another that displays an alert

    ∇ Compose
      :Access Public

     ⍝ The first button (b1)
      b1←'b1'Add _SF.ejButton'Toggle its state →'
      'type'b1.Set'ej.ButtonType.Button'
      b1.On'click' 'myCallback'

     ⍝ The second button (b2)
      b2←Add _SF.ejButton'Show alert'
      b2.id←'b2'
      'type' 'enabled'b2.Set'ej.ButtonType.Button'_false
      b2.On'click' 'myCallback'
    ∇

    ∇ r←myCallback
      :Access public
     ⍝ This callback simply flips b2's state when b1 is clicked
      :If 'b1'≡_what
          r←'enabled'b2.Update⊃_true _false~b2.GetOption'enabled'
      :Else
          r←Execute'alert("Hi there!")'
      :EndIf

    ∇

:EndClass

Remove stop in ejButtonSimple

Remove stop in ejButtonSimple


:Class DataTable : #._JQ._jqWidget
⍝ Description:: Enhanced HTML table using DataTables from https://www.datatables.net/
⍝ Constructor:: [Data [CellAttr [HeaderRows [HeaderAttr [MakeCellIds [MakeRowIds]]]]]
⍝               Constructor arguments are identical to those for #._DC.Table
⍝
⍝ Public Fields::
⍝ Data        - matrix of data to display in the table
⍝ CellAttr    - Cell Attributes
⍝ HeaderRows  - # of header rows
⍝ HeaderAttr  - Header attributes
⍝ MakeCellIds - 1 to generate IDs
⍝ MakeRowIds  - 1 to generate Row IDs

    :field public Data←0 0⍴⊂''
    :field public CellAttr←''
    :field public HeaderRows←1
    :field public HeaderAttr←''
    :field public MakeCellIds←0
    :field public MakeRowIds←0

    ∇ Make0
      :Access public
      JQueryFn←Uses←'DataTable'
      :Implements constructor
    ∇

    ∇ Make1 args
      :Access public
      JQueryFn←Uses←'DataTable'
      :Implements Constructor
      :If 2=⍴⍴args ⋄ args←,⊂args ⋄ :EndIf
      Data CellAttr HeaderRows HeaderAttr MakeCellIds MakeRowIds←args defaultArgs Data CellAttr HeaderRows HeaderAttr MakeCellIds MakeRowIds
    ∇

    ∇ html←Render;tab
      :Access public
      SetId
      Selector←'#',id
      :If 'true'≡⍕GetOption'searchHighlight'
          Use'jquery.Highlight'
          Use'⍎/DataTables/extras/searchHighlight/DataTables.searchHighlight.min.js'
          Use'⍕/DataTables/extras/searchHighlight/DataTables.searchHighlight.css'
      :EndIf
      (tab←⎕NEW #._DC.Table(Data CellAttr HeaderRows HeaderAttr MakeCellIds MakeRowIds)).id←id
      html←(tab.Render),⎕BASE.Render

⍝ BPB - to be sorted out with Michael
⍝      ⍝***** the following should be optional!
⍝      ⍝
⍝      ⍝ only applied if Options.searchHighlight=#.JSON.true
⍝      'DataTables_searchHighlight'{6::⍺ ∇ 1↓⍵ ⋄ 0<⍴⍵:(1⊃⍵).Use ⍺}⎕RSI
⍝      ⍝ only needed when Options.sDom contains 'W'
⍝      '⍎/DataTables/extras/ColumnFilterWidgets/media/js/ColumnFilterWidgets.js'{6::⍺ ∇ 1↓⍵ ⋄ 0<⍴⍵:(1⊃⍵).Use ⍺}⎕RSI
⍝      '⍕/DataTables/extras/ColumnFilterWidgets/media/css/ColumnFilterWidgets.css'{6::⍺ ∇ 1↓⍵ ⋄ 0<⍴⍵:(1⊃⍵).Use ⍺}⎕RSI

    ∇

:EndClass

:Class DataTable : #._JQ._jqWidget
⍝ Description:: Enhanced searchable and reorderable HTML table
⍝ Constructor:: [Data [CellAttr [HeaderRows [HeaderAttr [MakeCellIds [MakeRowIds]]]]]
⍝ Notes:: Constructor arguments are identical to those for _.Table
⍝ Public Fields::
⍝ Data        - matrix of data to display in the table
⍝ CellAttr    - Cell Attributes
⍝ HeaderRows  - # of header rows
⍝ HeaderAttr  - Header attributes
⍝ MakeCellIds - 1 to generate IDs
⍝ MakeRowIds  - 1 to generate Row IDs

    :Field public shared readonly DocBase←'https://www.datatables.net/'
    :field public Data←0 0⍴⊂''
    :field public CellAttr←''
    :field public HeaderRows←1
    :field public HeaderAttr←''
    :field public MakeCellIds←0
    :field public MakeRowIds←0

    ∇ Make0
      :Access public
      JQueryFn←Uses←'DataTable'
      :Implements constructor
    ∇

    ∇ Make1 args
      :Access public
      JQueryFn←Uses←'DataTable'
      :Implements Constructor
      :If 2=⍴⍴args ⋄ args←,⊂args ⋄ :EndIf
      Data CellAttr HeaderRows HeaderAttr MakeCellIds MakeRowIds←args defaultArgs Data CellAttr HeaderRows HeaderAttr MakeCellIds MakeRowIds
    ∇

    ∇ html←Render;tab
      :Access public
      SetId
      Selector←'#',id
      :If 'true'≡⍕GetOption'searchHighlight'
          Use'jquery.Highlight'
          Use'⍎/DataTables/extras/searchHighlight/DataTables.searchHighlight.min.js'
          Use'⍕/DataTables/extras/searchHighlight/DataTables.searchHighlight.css'
      :EndIf
      (tab←⎕NEW #._DC.Table(Data CellAttr HeaderRows HeaderAttr MakeCellIds MakeRowIds)).id←id
      html←(tab.Render),⎕BASE.Render

⍝ BPB - to be sorted out with Michael
⍝      ⍝***** the following should be optional!
⍝      ⍝
⍝      ⍝ only applied if Options.searchHighlight=#.JSON.true
⍝      'DataTables_searchHighlight'{6::⍺ ∇ 1↓⍵ ⋄ 0<⍴⍵:(1⊃⍵).Use ⍺}⎕RSI
⍝      ⍝ only needed when Options.sDom contains 'W'
⍝      '⍎/DataTables/extras/ColumnFilterWidgets/media/js/ColumnFilterWidgets.js'{6::⍺ ∇ 1↓⍵ ⋄ 0<⍴⍵:(1⊃⍵).Use ⍺}⎕RSI
⍝      '⍕/DataTables/extras/ColumnFilterWidgets/media/css/ColumnFilterWidgets.css'{6::⍺ ∇ 1↓⍵ ⋄ 0<⍴⍵:(1⊃⍵).Use ⍺}⎕RSI

    ∇

:EndClass

restructure of internal doc

DataTable: restructure of internal doc


:Class DataTable : #._JQ._jqWidget
⍝ Description:: Enhanced searchable and reorderable HTML table
⍝ Constructor:: [data [cellAttr [headerRows [headerAttr [makeCellIds [makeRowIds]]]]]
⍝ Note that constructor arguments are identical to those for Table
⍝ data        - matrix of data to display in the table
⍝ cellAttr    - Cell Attributes
⍝ headerRows  - # of header rows
⍝ headerAttr  - Header attributes
⍝ makeCellIds - 1 to generate IDs
⍝ makeRowIds  - 1 to generate Row IDs

⍝ Public Fields::
⍝ Data        - matrix of data to display in the table
⍝ CellAttr    - Cell Attributes
⍝ HeaderRows  - # of header rows
⍝ HeaderAttr  - Header attributes
⍝ MakeCellIds - 1 to generate IDs
⍝ MakeRowIds  - 1 to generate Row IDs

    :Field public shared readonly DocBase←'https://www.datatables.net/'
    :field public Data←0 0⍴⊂''
    :field public CellAttr←''
    :field public HeaderRows←1
    :field public HeaderAttr←''
    :field public MakeCellIds←0
    :field public MakeRowIds←0

    :field public Plugins←''     ⍝ comma delimited list of "official" plugins to use
    :field private JSON_Data←''   ⍝ supporting JSON-Data transparently ("Data" can be JSON)

    ∇ Make0
      :Access public
      JQueryFn←Uses←'DataTable'
      :Implements constructor
      Container←⎕NEW #._DC.Table
      ContainerTag←'table'
    ∇

    ∇ Make1 args
      :Access public
      JQueryFn←Uses←'DataTable'
      :Implements Constructor
      :If 2=⍴⍴args ⋄ args←,⊂args ⋄ :EndIf
      Data CellAttr HeaderRows HeaderAttr MakeCellIds MakeRowIds←args defaultArgs Data CellAttr HeaderRows HeaderAttr MakeCellIds MakeRowIds
      :If 2≠⍴⍴Data
      :AndIf #.HtmlElement.isChar Data
          JSON_Data←Data ⋄ Data←0 0⍴0
      :EndIf
      Container←⎕NEW #._DC.Table
      ContainerTag←'table'
    ∇

    ∇ html←Render;tab
      :Access public
⍝∘∘∘
      :If _true≡GetOption'mark'
       Use'DataTable_mark'
       SetUse
        :EndIf

      opts←Options
      JavaScript,←RenderPlugins
      Options←opts
      :If 0<⍴JSON_Data ⋄ 'data'Set⊂JSON_Data ⋄ :EndIf
      Container.(Data CellAttr HeaderRows HeaderAttr MakeCellIds MakeRowIds)←(Data CellAttr HeaderRows HeaderAttr MakeCellIds MakeRowIds)
      html←⎕BASE.Render

    ∇

    ∇ js←RenderPlugins;plugin
    ⍝ might also update Options
      js←''
      :For plugin :In ','#.Utils.penclose Plugins
          :Select plugin
          :Case 'yadcf'
              js,←yadcfRender
              Options.⎕EX'yadcf'
          :EndSelect
      :EndFor
    ∇

    :section yadcf Plugin
    ∇ js←yadcfRender;flt
      js←''
      :If 0<Options.⎕NC'yadcf.Filters'
      :AndIf 0<⍴Options.yadcf.Filters
          Uses←'DataTable_yadcf'
          flt←#.JSON.fromAPL Options.yadcf.Filters
          :If ∨/'"chosen"'⍷flt ⋄ Use'chosen' ⋄ :EndIf     ⍝ load Chosen-Plugin for yadcf-Filters
          js←';yadcf.init($("#',id,'").DataTable(),',flt,');'
      :EndIf
    ∇
    :endsection

:EndClass

:Class DataTable : #._JQ._jqWidget
⍝ Description:: Enhanced searchable and reorderable HTML table
⍝ Constructor:: [data [cellAttr [headerRows [headerAttr [makeCellIds [makeRowIds]]]]]
⍝ Note that constructor arguments are identical to those for Table
⍝ data        - matrix of data to display in the table
⍝ cellAttr    - Cell Attributes
⍝ headerRows  - # of header rows
⍝ headerAttr  - Header attributes
⍝ makeCellIds - 1 to generate IDs
⍝ makeRowIds  - 1 to generate Row IDs

⍝ Public Fields::
⍝ Data        - matrix of data to display in the table
⍝ CellAttr    - Cell Attributes
⍝ HeaderRows  - # of header rows
⍝ HeaderAttr  - Header attributes
⍝ MakeCellIds - 1 to generate IDs
⍝ MakeRowIds  - 1 to generate Row IDs

    :Field public shared readonly DocBase←'https://www.datatables.net/'
    :field public Data←0 0⍴⊂''
    :field public CellAttr←''
    :field public HeaderRows←1
    :field public HeaderAttr←''
    :field public MakeCellIds←0
    :field public MakeRowIds←0

    :field public Plugins←''     ⍝ comma delimited list of "official" plugins to use
    :field private JSON_Data←''   ⍝ supporting JSON-Data transparently ("Data" can be JSON)

    ∇ Make0
      :Access public
      JQueryFn←Uses←'DataTable'
      :Implements constructor
      Container←⎕NEW #._DC.Table
      ContainerTag←'table'
    ∇

    ∇ Make1 args
      :Access public
      JQueryFn←Uses←'DataTable'
      :Implements Constructor
      :If 2=⍴⍴args ⋄ args←,⊂args ⋄ :EndIf
      Data CellAttr HeaderRows HeaderAttr MakeCellIds MakeRowIds←args defaultArgs Data CellAttr HeaderRows HeaderAttr MakeCellIds MakeRowIds
      :If 2≠⍴⍴Data
      :AndIf #.HtmlElement.isChar Data
          JSON_Data←Data ⋄ Data←0 0⍴0
      :EndIf
      Container←⎕NEW #._DC.Table
      ContainerTag←'table'
    ∇

    ∇ html←Render;tab
      :Access public
⍝∘∘∘
      :If _true≡GetOption'mark'
       Use'DataTable_mark'
       SetUse
        :EndIf

      opts←Options
      JavaScript,←RenderPlugins
      Options←opts
      :If 0<⍴JSON_Data ⋄ 'data'Set⊂JSON_Data ⋄ :EndIf
      Container.(Data CellAttr HeaderRows HeaderAttr MakeCellIds MakeRowIds)←(Data CellAttr HeaderRows HeaderAttr MakeCellIds MakeRowIds)
      html←⎕BASE.Render

    ∇

    ∇ js←RenderPlugins;plugin
    ⍝ might also update Options
      js←''
      :For plugin :In ','#.Utils.penclose Plugins
          :Select plugin
          :Case 'yadcf'
              js,←yadcfRender
              Options.⎕EX'yadcf'
          :EndSelect
      :EndFor
    ∇

    :section yadcf Plugin
    ∇ js←yadcfRender;flt
      js←''
      :If 0<Options.⎕NC'yadcf.Filters'
      :AndIf ×≢Options.yadcf.Filters
          Uses←'DataTable_yadcf'
          flt←#.JSON.fromAPL Options.yadcf.Filters
          :If ∨/'"chosen"'⍷flt ⋄ Use'chosen' ⋄ :EndIf     ⍝ load Chosen-Plugin for yadcf-Filters
          js←';yadcf.init($("#',id,'").DataTable(),',flt,');'
      :EndIf
    ∇
    :endsection

:EndClass

Handle scalar yadcf.Filters

DataTable: Handle scalar yadcf.Filters


:Namespace SeleniumTests

    ∇ x←eis x
⍝ Enclose if simple
      :If (≡x)∊0 1 ⋄ x←,⊂,x ⋄ :EndIf
    ∇

    ∇ r←lopFirst url
    ⍝ remove first segment of URL
      r←{⍵/⍨(1+'/'=1↑⍵)≤+\'/'=⍵}url
    ∇

    ∇ r←Run1Test page;name;ref;Test
     ⍝ eg MS3Test '/QA/DC/InputGridSimple'

      Selenium.GoTo SITE,lopFirst page ⍝ Drop the "QA"
      :If 'Test'≡name←⎕SE.SALT.Load AppRoot,page
          :Trap stopOnError×9999
              :If stopOnError∧0≠⍴r←Test ⍬
                  ⎕←'test for ',page,' failed:' ⋄ ⎕←r ⋄ ⎕←'Rerun:' ⋄ '      Test ⍬'
                  ∘∘∘
              :EndIf
          :Else
              r←'Trapped error: ',,⍕⎕DMX.EN
          :EndTrap
      :Else ⋄ r←AppRoot,page,' does not define a function called Test'
      :EndIf
    ∇

    ∇ r←FindAllFiles root;folders;ext
      :If 0=⎕NC'Config.DefaultExtension' ⋄ ext←'.dyalog'
      :Else ⋄ ext←Config.DefaultExtension
      :EndIf
      root,←'/'/⍨~'/\'∊⍨¯1↑root ⍝ append trailing / if missing
      r←root∘,¨(('*',ext)#.Files.List root)[;1]
      :If 0≠⍴folders←{(('.'≠⊃¨⍵[;1])∧⍵[;4])/⍵[;1]}#.Files.List root
          r←r,⊃,/FindAllFiles¨root∘,¨folders
      :EndIf
    ∇

    ∇ r←{stopOnError}Test site;count;ctl;examples;f;fail;nodot;start;t;time;z;i;START;COUNT;FAIL;Config;selpath;files;n;ext;filter;⎕PATH;keynames;maxlen;⎕USING
      r←''
      (site filter)←2↑(eis site),'' ''
      :If 0=⍴AppRoot←#.Load site
          ⎕←'Test abandoned' ⋄ →0
      :EndIf

      selpath←({∊'/',⍨¨¯1↓'/\'#.Utils.penclose ⍵}#.Boot.MSRoot),'Selenium/'
      :If 0=⎕NC'Selenium'
          :Trap 0 ⋄ ⎕SE.SALT.Load selpath,'/Selenium'
          :Else
              ⎕←'Selenium library not found at: ',selpath
              →0⍴⍨0∊⍴selpath←{⍞↓⍨⍴⍞←⍵,': '}'Selenium path'
              :Trap 0 ⋄ ⎕SE.SALT.Load selpath,'/Selenium'
              :Else ⋄ ⎕←'Unable to load Selenium' ⋄ →0
              :EndTrap
          :EndTrap
      :EndIf
      ⎕PATH,←' Selenium'
      Selenium.DLLPATH←selpath

      Config←#.Boot.ConfigureServer AppRoot
      ext←Config.DefaultExtension
      Config.DefaultExtension←'.dyalog' ⍝ We are searching for code
      n←⍴files←(⍴AppRoot)↓¨¯7↓¨FindAllFiles AppRoot,'QA'
      ⍝ // Add code to compare this to the mipages found in the whole app
      :If 0≠⍴filter
          files←(filter ⎕S'%')files
          ⎕←'Selected: ',(⍕⍴files),' of ',(⍕n),' tests.'
      :EndIf
      n←⍴files
      SITE←'http://127.0.0.1:',⍕Config.Port

⍝⍝ Un-comment to play music while testing:
⍝      :If site filter≡'MS3' ''
⍝          ⎕CMD('"\Program Files (x86)\Windows Media Player\wmplayer.exe" "',AppRoot,'\Examples\Data\tellintro.mp3"')''
⍝      :EndIf

      Selenium.InitBrowser''
      Selenium.BROWSER.Manage.Window.Maximize

     ⍝ Localize non-alphanumeric key names for easy access
      keynames←⍕#.SeleniumTests.Selenium.Keys.⎕NL ¯2
      ⍎keynames,'←∊#.SeleniumTests.Selenium.Keys.(',keynames,')'

      START←⎕AI[3] ⋄ COUNT←0 ⋄ FAIL←0
      maxlen←¯2+⌈/⊃∘⍴¨files

      :For i :In ⍳n
          COUNT+←1
          :If 0=⍴t←Run1Test{⍵⊣⍞←(⎕UCS 13),maxlen↑lopFirst ⍵}z←i⊃files
              ⍞←'*** PASSED ***'
          :Else
              FAIL+←1
              r,←⊂z
              ⍞←'*** FAILED *** #',(⍕i),' of ',(⍕n),': ',z,': ',t
          :EndIf
      :EndFor

      ⎕←'Total of ',(⍕COUNT),' samples tested in ',(∊(⍕¨24 60⊤⌊0.5+(⎕AI[3]-START)÷1000),¨'ms'),': ',(⍕FAIL),' failed.'

      Selenium.BROWSER.Quit
    ∇

:EndNamespace

:Namespace SeleniumTests

    ∇ x←eis x
⍝ Enclose if simple
      :If (≡x)∊0 1 ⋄ x←,⊂,x ⋄ :EndIf
    ∇

    ∇ r←lopFirst url
    ⍝ remove first segment of URL
      r←{⍵/⍨(1+'/'=1↑⍵)≤+\'/'=⍵}url
    ∇

    ∇ r←Run1Test page;name;ref;Test
     ⍝ eg MS3Test '/QA/DC/InputGridSimple'

      Selenium.GoTo SITE,lopFirst page ⍝ Drop the "QA"
      :If 'Test'≡name←⎕SE.SALT.Load AppRoot,page
          :Trap stopOnError×9999
              :If stopOnError∧0≠⍴r←Test ⍬
                  ⎕←'test for ',page,' failed:' ⋄ ⎕←r ⋄ ⎕←'Rerun:' ⋄ '      Test ⍬'
                  ∘∘∘
              :EndIf
          :Else
              r←'Trapped error: ',,⍕⎕DMX.EN
          :EndTrap
      :Else ⋄ r←AppRoot,page,' does not define a function called Test'
      :EndIf
    ∇

    ∇ r←FindAllFiles root;folders;ext
      :If 0=⎕NC'Config.DefaultExtension' ⋄ ext←'.dyalog'
      :Else ⋄ ext←Config.DefaultExtension
      :EndIf
      root,←'/'/⍨~'/\'∊⍨¯1↑root ⍝ append trailing / if missing
      r←root∘,¨(('*',ext)#.Files.List root)[;1]
      :If 0≠⍴folders←{(('.'≠⊃¨⍵[;1])∧⍵[;4])/⍵[;1]}#.Files.List root
          r←r,⊃,/FindAllFiles¨root∘,¨folders
      :EndIf
    ∇

    ∇ r←stopOnError_port Test site;count;ctl;examples;f;fail;nodot;start;t;time;z;i;START;COUNT;FAIL;Config;selpath;files;n;ext;filter;⎕PATH;keynames;maxlen;⎕USING;stopOnError
      stopOnError←⊃stopOnError_port
      r←''
      (site filter)←2↑(eis site),'' ''
      :If 0=⍴AppRoot←#.Load site
          ⎕←'Test abandoned' ⋄ →0
      :EndIf

      selpath←({∊'/',⍨¨¯1↓'/\'#.Utils.penclose ⍵}#.Boot.MSRoot),'Selenium/'
      :If 0=⎕NC'Selenium'
          :Trap 0 ⋄ ⎕SE.SALT.Load selpath,'/Selenium'
          :Else
              ⎕←'Selenium library not found at: ',selpath
              →0⍴⍨0∊⍴selpath←{⍞↓⍨⍴⍞←⍵,': '}'Selenium path'
              :Trap 0 ⋄ ⎕SE.SALT.Load selpath,'/Selenium'
              :Else ⋄ ⎕←'Unable to load Selenium' ⋄ →0
              :EndTrap
          :EndTrap
      :EndIf
      ⎕PATH,←' Selenium'
      Selenium.DLLPATH←selpath

      Config←#.Boot.ConfigureServer AppRoot
      ext←Config.DefaultExtension
      Config.DefaultExtension←'.dyalog' ⍝ We are searching for code
      n←⍴files←(⍴AppRoot)↓¨¯7↓¨FindAllFiles AppRoot,'QA'
      ⍝ // Add code to compare this to the mipages found in the whole app
      :If 0≠⍴filter
          files←(filter ⎕S'%')files
          ⎕←'Selected: ',(⍕⍴files),' of ',(⍕n),' tests.'
      :EndIf
      n←⍴files
      SITE←'http://127.0.0.1:',⍕⊃1↓stopOnError_port,Config.Port

⍝⍝ Un-comment to play music while testing:
⍝      :If site filter≡'MS3' ''
⍝          ⎕CMD('"\Program Files (x86)\Windows Media Player\wmplayer.exe" "',AppRoot,'\Examples\Data\tellintro.mp3"')''
⍝      :EndIf

      Selenium.InitBrowser''
      Selenium.BROWSER.Manage.Window.Maximize

     ⍝ Localize non-alphanumeric key names for easy access
      keynames←⍕#.SeleniumTests.Selenium.Keys.⎕NL ¯2
      ⍎keynames,'←∊#.SeleniumTests.Selenium.Keys.(',keynames,')'

      START←⎕AI[3] ⋄ COUNT←0 ⋄ FAIL←0
      maxlen←¯2+⌈/⊃∘⍴¨files

      :For i :In ⍳n
          COUNT+←1
          :If 0=⍴t←Run1Test{⍵⊣⍞←(⎕UCS 13),maxlen↑lopFirst ⍵}z←i⊃files
              ⍞←'*** PASSED ***'
          :Else
              FAIL+←1
              r,←⊂z
              ⍞←'*** FAILED *** #',(⍕i),' of ',(⍕n),': ',z,': ',t
          :EndIf
      :EndFor

      ⎕←'Total of ',(⍕COUNT),' samples tested in ',(∊(⍕¨24 60⊤⌊0.5+(⎕AI[3]-START)÷1000),¨'ms'),': ',(⍕FAIL),' failed.'

      Selenium.BROWSER.Quit
    ∇

:EndNamespace

Test (Selenium) now allows specifying a port number after the Stop-On-Error Boolean (was always-8080).


⍝ Using the ⍳ (iota) function to generate a set of ordered numbers in a 3D array
⍳ 9 9 9

Update iota999.apl

Update iota999.apl


:Class ejDatePicker : #._SF._ejWidget
⍝ Description:: Syncfusion DatePicker widget
⍝ Constructor:: [date [format]]
⍝ date          -  date in JavaScript format (see: http://www.w3schools.com/js/js_dates.asp)  (default 3↑⎕TS)
⍝ format        -  (default 'yyyy/MM/dd')
⍝ Public Fields::
⍝ Label    - string of text to appear next to the input field
⍝ LabelPos - position of label relative to the date input field ('left' (default) or 'right')
⍝ Examples::
⍝ ejDatePicker
⍝ ejDatePicker '27-Nov-1966'
⍝ ejDatePicker (2000 1 1)('dd-MMM-yyyy')

    :Field Public Shared ReadOnly DocBase←'http://help.syncfusion.com/js/api/ejDatePicker.html'
    :Field Public Shared ReadOnly ApiLevel←3
    :Field Public Shared ReadOnly DocDyalog←'/Documentation/DyalogAPIs/Syncfusion/ejDatePicker.html'
    :Field Public Shared ReadOnly IntEvt←'beforeDateCreate'  'change'  'close'  'create'  'destroy'  'focusIn'  'focusOut'  'open'  'select'
    :field public Label←''
    :field public LabelPos←'left'  ⍝ valid are 'left' 'right'

    ∇ make0
      :Access Public
      JQueryFn←Uses←'ejDatePicker'
      ContainerTag←'input'
      :Implements Constructor
      Container.type←'text'
      InternalEvents←IntEvt
    ∇

    ∇ make args;val;fmt
    ⍝ Selector [value [dateFormat]]
      :Access Public
      JQueryFn←Uses←'ejDatePicker'
      ContainerTag←'input'
      :Implements Constructor
      args←(⊂⍣(3=10|⎕DR args))args
      (val fmt)←args defaultArgs(3↑⎕TS)'yyyy/MM/dd'
      ('value' 'dateFormat')Set(('⍎new Date("',(⍕val),'")')fmt)
      Container.type←'text'
      InternalEvents←IntEvt
    ∇

    ∇ r←Render
      :Access public
      Container.NoEndTag←1
      SetId
      r←⎕BASE.Render
      :If Label≢''
          r←r((LabelPos≡'right'){⍺⍺:⍺,⍵ ⋄ ⍵,⍺})(⎕NEW #._html.label(Label('for'id))).Render
      :EndIf
    ∇

:EndClass

:Class ejDatePicker : #._SF._ejWidget
⍝ Description:: Syncfusion DatePicker widget
⍝ Constructor:: [date [format]]
⍝ date          -  date in JavaScript format (see: http://www.w3schools.com/js/js_dates.asp)  (default 3↑⎕TS)
⍝ format        -  (default 'yyyy/MM/dd')
⍝ Public Fields::
⍝ Label    - string of text to appear next to the input field
⍝ LabelPos - position of label relative to the date input field ('left' (default) or 'right')
⍝ Examples::
⍝ ejDatePicker
⍝ ejDatePicker '27-Nov-1966'
⍝ ejDatePicker (2000 1 1)('dd-MMM-yyyy')

    :Field Public Shared ReadOnly DocBase←'http://help.syncfusion.com/js/api/ejDatePicker.html'
    :Field Public Shared ReadOnly ApiLevel←3
    :Field Public Shared ReadOnly DocDyalog←'/Documentation/DyalogAPIs/Syncfusion/ejDatePicker.html'
    :Field Public Shared ReadOnly IntEvt←'beforeDateCreate'  'change'  'close'  'create'  'destroy'  'focusIn'  'focusOut'  'open'  'select'
    :field public Label←''
    :field public LabelPos←'left'  ⍝ valid are 'left' 'right'

    ∇ make0
      :Access Public
      JQueryFn←Uses←'ejDatePicker'
      ContainerTag←'input'
      :Implements Constructor
      Container.type←'text'
      InternalEvents←IntEvt
    ∇

    ∇ make args;val;fmt
    ⍝ Selector [value [dateFormat]]
      :Access Public
      JQueryFn←Uses←'ejDatePicker'
      ContainerTag←'input'
      :Implements Constructor
      args←(⊂⍣(3=10|⎕DR args))args
      (val fmt)←args defaultArgs(3↑⎕TS)'yyyy/MM/dd'
      ('value' 'dateFormat')Set(('⍎new Date("',(⍕val),'")')fmt)
      Container.type←'text'
      InternalEvents←IntEvt
    ∇

    ∇ r←Render
      :Access public
      Container.NoEndTag←1
      SetId
      r←⎕BASE.Render
      :If Label≢''
          r←r((LabelPos≡'right'){⍺⍺:⍺,⍵ ⋄ ⍵,⍺})(⎕NEW #._html.label(Label('for=',id))).Render
      :EndIf
    ∇

:EndClass

Fix label creation syntax for ejDatePicker


:Namespace Dates

    (⎕ML ⎕IO)←1

    ∇ r←CookieFmt date;day;date;mon
         ⍝ Format date for cookie expiry
         ⍝ "expires Mon, 09-Dec-2002 13:46:00 GMT"

      day←(7 3⍴'MonTueWedThuFriSatSun')[WeekDay date;]
      mon←(12 3⍴'janfebmaraprmayjunjulaugsepoctnovdec')[2⊃date;]
      r←,('<',day,', >,ZI2,<-',mon,'->,ZI4,< >,ZI2,<:>,ZI2,<:>,ZI2,< GMT>')⎕FMT 1 5⍴(6↑date)[3 1 4 5 6]
    ∇

    ∇ SetUtcOffset;ver;⎕USING
      :If 0=⎕NC'_UtcOffset'
          :If 'Win'≡ver←3↑1⊃'.'⎕WG'APLVersion'
              :Hold '_UtcOffset'
                  ⎕USING←,⊂''
                  _UtcOffset←¯60×(System.TimeZone.CurrentTimeZone.GetUtcOffset ⎕NEW System.DateTime(⎕TS)).Hours
              :EndHold
          :Else
              :If (⊂ver)∊'Lin' 'AIX' 'Sol' 'Mac'
                  _UtcOffset←¯60×.01×⍎⊃⎕SH'date +%z'
              :Else
                  _UtcOffset←0 ⍝ otherwise, assume GMT
              :EndIf
          :EndIf
      :EndIf
    ∇

    ∇ r←{minOffset}HTTPDate ts;sign;day;mon;ver;⎕USING;t
    ⍝ return RCF 1123/822 compliant date
    ⍝ minOffset is option number of minutes to offset time with (used for HTTP caching expirations)
      minOffset←{0::0 ⋄ minOffset}''
      ts←6↑ts
      SetUtcOffset
      ts←IDNToDate((_UtcOffset+minOffset)÷24×60)+t←DateToIDN ts
      day←(7 3⍴'MonTueWedThuFriSatSun')[1+7|(⌊t)-1;]
      mon←(12 3⍴'JanFebMarAprMayJunJulAugSepOctNovDec')[2⊃ts;]
      r←,('<',day,', >,ZI2,< ',mon,' >,ZI4,< >,ZI2,<:>,ZI2,<:>,ZI2,< GMT>')⎕FMT 1 5⍴ts[3 1 4 5 6]
    ∇

    ∇ SM←DateToIDN TS                  ⍝ Convert date format
      SM←2 ⎕NQ'.' 'DateToIDN'(3↑TS)
      :If 3<⍴TS
          SM+←(24 60 60 1000⊥4↑3↓TS)÷86400000
      :EndIf
    ∇

    ∇ TS←IDNToDate SM                ⍝ Convert IDN to date format : 3↑⎕TS ← IDN (akd TS_SM)
      TS←3↑2 ⎕NQ'.' 'IDNToDate'(⌊SM)
      TS,←⌊0.5+24 60 60 1000⊤86400000×1|SM
    ∇

    ∇ new←ts IdnAdd t
    ⍝ T is D HH MM SS
      new←ts+(0 24 60 60 1000⊥¯5↑t,0)÷86400000
    ∇

    ∇ r←Now
      r←DateToIDN ⎕TS
    ∇

    ∇ r←TSFmt ts
      r←,'ZI4,<->,ZI2,<->,ZI2,< >,ZI2,<:>,ZI2,<:>,ZI2'⎕FMT 1 6⍴6↑ts
    ∇

    ∇ r←TSFmtNice ts;now;yday;today;z;i;m;idn;s
    ⍝ Format a vector of IDN's nicely
      s←⍴ts
      yday←¯1+today←⌊now←DateToIDN ⎕TS
      r←↑IDNToDate¨,ts←,ts ⍝ Make matrix
      r←'ZI4,<->,ZI2,<->,ZI2,< >,ZI2,<:>,ZI2'⎕FMT 5↑[2]r
      :If 0≠⍴i←((ts≥yday)∧~m←ts≥today)/⍳⍴ts
          r[i;]←r[i;11+⍳5],' ',((⍴i),10)⍴10↑'Yesterday'
      :EndIf
      :If 0≠⍴i←m/⍳⍴ts
          r[i;]←r[i;11+⍳5],' ',((⍴i),10)⍴10↑'Today'
      :EndIf
      :If 0≠⍴i←(100>z←⌊(now-ts)×24×60)/⍳⍴ts
          r[i;]←16↑[2]↑(⍕¨⌊z[i]),¨(' minutes ago' ' minute ago')[1+1=z[i]]
      :EndIf
      :If 0≠⍴i←(z<1)/⍳⍴ts
          r[i;]←((⍴i),16)⍴16↑'Now'
      :EndIf
      r←(s,¯1↑⍴r)⍴r
    ∇

    ∇ r←WeekDay Date
    ⍝ Return weekday (Monday=1, Sunday=7)
      r←1+7|(DateToIDN 3↑Date)-1
    ∇

    ∇ r←{opt}DateFormat ymd
    ⍝ opt - 0 dd MMM yyyy
    ⍝       1 dd Month yyyy
      :If 0=⎕NC'opt' ⋄ opt←0 ⋄ :EndIf
      :Select ⊃opt
      :Case 0
          r←(⍕ymd[3]),(1⌽'  ',3↑(3×¯1+ymd[2])↓'JANFEBMARAPRMAYJUNJULAUGSEPOCTNOVDEC'),⍕ymd[1]
      :Case 1
          r←(⍕ymd[3]),(1⌽'  ',ymd[2]⊃'January' 'February' 'March' 'April' 'May' 'June' 'July' 'August' 'September' 'October' 'November' 'December'),⍕ymd[1]
      :Else
          r←⍕ymd
      :EndSelect
    ∇

    ∇ r←LogFmtNow;ver
    ⍝ returns now UTC adjusted, and formatted for log files (Common Log Format)
      :If 'Win'≡ver←3↑1⊃'.'⎕WG'APLVersion'
          r←((⍎⎕NA'kernel32|GetSystemTime >{U2 U2 U2 U2 U2 U2 U2 U2}')⊂8⍴0)[4 2 1 5 6 7]
          r[2]←⊂(12 3⍴'JanFebMarAprMayJunJulAugSepOctNovDec')[,2⊃r;]
          r←,'< [>,ZI2,</>,3A1,</>,ZI4,<:>,ZI2,<:>,ZI2,<:>,ZI2,< +0000] >'⎕FMT r
      :Else
          r←1⊃⎕SH'date +" [%d/%b/%Y:%T %z] "'
      :EndIf
    ∇

    ∇ r←LogFmt ymdhms
      r←ymdhms[3 2 1 4 5 6]
      r[2]←⊂(12 3⍴'JanFebMarAprMayJunJulAugSepOctNovDec')[,2⊃r;]
      r←,'< [>,ZI2,</>,3A1,</>,ZI4,<:>,ZI2,<:>,ZI2,<:>,ZI2,< +0000] >'⎕FMT r
    ∇

    ∇ ts←FTT fts;md;shape;tmp;yr;z;⎕IO
     ⍝ *** convert ⎕FRDCI/⎕FHIST timestamp(s) to ⎕ts-format for Dyalog/W ***
     ⍝ right argument: ⎕FRDCI-type timestamp(s) of any shape
     ⍝ result: ⎕ts-type timestamp(s) with shape <(⍴argument),7>
      ⎕IO←0 ⋄ shape←⍴fts ⋄ ts←,fts+18626112000
      md←365.2501|1+1461|yr←⌊ts÷5184000
      tmp←31 61 92 122 153 184 214 245 275 306 337 366
      z←(,⍉<⍀tmp∘.≥md)/,((⍴md),12)⍴⍳12
      md←(1+12|z+2),[0.1]⌈md-(0,tmp)[z]
      ts←(1960+⌊(yr+60)÷365.25),md,⍉24 60 60 60⊤ts
      ts[;6]←⌊0.5+ts[;6]×100÷6
      ts←(shape,7)⍴ts
    ∇

    ∇ r←TTF ts;l;h;d;m;y
       ⍝ convert a ⎕TS style timestamp into 60ths of a second since 1st January 1970 a la ⎕FRDCI
      l←⌈60×ts[7]÷1000                                         ⍝ convert milliseconds to 60ths
      h←3600 60 60⊥ts[4 5 6]                                   ⍝ hours minutes seconds to to the nearest seconds total
      d←ts[3]-1                                                ⍝ days since start of month
      m←(2⊃ts)⊃++\0 31,(28+0=4|⊃ts),31 30 31 30 31 31 30 31 30 ⍝ days in completed months
      y←{{(365×⍵)+⌈4÷⍨⍵-2}⍵-1970}⊃ts                           ⍝ days in years since 1970, leap years since 1972
      r←l+60×h+86400×y+m+d                                     ⍝ sum, convert to seconds, add seconds in the day convert to 60ths, add on 60ths
    ∇

    tonum←{(b v)←⎕vfi ⍵ ⋄ b/v}

    ∇ dt←ParseDate str;pos;mon;t;ymd
     ⍝ str is of the genre "Wed Aug 05 2015 07:30:21 GMT-0400 (Eastern Daylight Time)"
     ⍝ We need to weed out the day of the week and the time
      str←(+/∧\' '=str)↓str           ⍝ remove the leading spaces
     ⍝ What kind of string is this?
      :If ~∧/1⊃(dt dt)←{b←~⍵∊'/-:' ⋄ ⎕VFI b\b/⍵}str  ⍝ yyyy/mm/dd hh:mm:ss ?
          :If 0∊⍴t←'Jan' 'Feb' 'Mar' 'Apr' 'May' 'Jun' 'Jul' 'Aug' 'Sep' 'Oct' 'Nov' 'Dec'⎕S 0 3⊢str      ⍝ look for the month as a string. If not found
              ymd←3↑tonum str                ⍝ grab the 1st 3 numbers found
              ymd←ymd[⍒(2×31<ymd)+ymd<12] ⍝ put in correct order
          :Else                           ⍝ otherwise (if found)
              (pos mon)←0 1+1⊃t
              :If ~0∊⍴t←tonum pos↑str        ⍝ any number before the month? (e.g. 2 May 2021)
                  ymd←⌽⍣(31<⍬⍴t)⊢(1↑tonum pos↓str),mon,t
              :Else
                  ymd←¯1⌽mon,2↑tonum pos↓str
              :EndIf
          :EndIf
     ⍝ Now grab the time
          dt←ymd,tonum⍕'(\d+):(\d+):(\d+)'⎕S'\1 \2 \3'⊢str
      :EndIf
    ∇

    ∇ ts←ParseISODate str
      SetUtcOffset
      ts←IDNToDate(-_UtcOffset÷24×60)+DateToIDN 7↑str{⊃(//)⎕VFI ⍵\⍵/⍺}str∊⎕D
    ∇

    ∇ r←{unit}ParseTime string;chunks;units;factors
     ⍝ Parse time string into units (default is ms)
     ⍝ String is a string like '5d4h47m6s266ms'
      :If 0=⎕NC'unit' ⋄ unit←'ms' ⋄ :EndIf
      units←(1 1 1 1 1 0⊂'dhmsms'),⊂''
      factors←86400000 3600000 60000 1000 1 1
      chunks←{⎕ML←3 ⋄ (1+⍵∊⎕D)⊂⍵}string
      :Trap 0/0
          r←(⍎¨{⍵∩⎕D}¨chunks)+.×factors[units⍳{#.Strings.lc ⍵~⎕D}¨chunks]
      :Else
          'Invalid time string'⎕SIGNAL 11
      :EndTrap
      r←r÷factors[units⍳⊂,unit]
    ∇

:EndNamespace

:Namespace Dates

    (⎕ML ⎕IO)←1

    ∇ r←CookieFmt date;day;date;mon
         ⍝ Format date for cookie expiry
         ⍝ "expires Mon, 09-Dec-2002 13:46:00 GMT"

      day←(7 3⍴'MonTueWedThuFriSatSun')[WeekDay date;]
      mon←(12 3⍴'janfebmaraprmayjunjulaugsepoctnovdec')[2⊃date;]
      r←,('<',day,', >,ZI2,<-',mon,'->,ZI4,< >,ZI2,<:>,ZI2,<:>,ZI2,< GMT>')⎕FMT 1 5⍴(6↑date)[3 1 4 5 6]
    ∇

    ∇ SetUtcOffset;ver;⎕USING
      :If 0=⎕NC'_UtcOffset'
          :If 'Win'≡ver←3↑1⊃'.'⎕WG'APLVersion'
              :Hold '_UtcOffset'
                  ⎕USING←,⊂''
                  _UtcOffset←¯60×(System.TimeZone.CurrentTimeZone.GetUtcOffset ⎕NEW System.DateTime(⎕TS)).Hours
              :EndHold
          :Else
              :If (⊂ver)∊'Lin' 'AIX' 'Sol' 'Mac'
                  _UtcOffset←¯60×.01×⍎⊃⎕SH'date +%z'
              :Else
                  _UtcOffset←0 ⍝ otherwise, assume GMT
              :EndIf
          :EndIf
      :EndIf
    ∇

    ∇ r←{minOffset}HTTPDate ts;sign;day;mon;ver;⎕USING;t
    ⍝ return RCF 1123/822 compliant date
    ⍝ minOffset is option number of minutes to offset time with (used for HTTP caching expirations)
      minOffset←{0::0 ⋄ minOffset}''
      ts←6↑ts
      SetUtcOffset
      ts←IDNToDate((_UtcOffset+minOffset)÷24×60)+t←DateToIDN ts
      day←(7 3⍴'MonTueWedThuFriSatSun')[1+7|(⌊t)-1;]
      mon←(12 3⍴'JanFebMarAprMayJunJulAugSepOctNovDec')[2⊃ts;]
      r←,('<',day,', >,ZI2,< ',mon,' >,ZI4,< >,ZI2,<:>,ZI2,<:>,ZI2,< GMT>')⎕FMT 1 5⍴ts[3 1 4 5 6]
    ∇

    ∇ SM←DateToIDN TS                  ⍝ Convert date format
      SM←2 ⎕NQ'.' 'DateToIDN'(3↑TS)
      :If 3<⍴TS
          SM+←(24 60 60 1000⊥4↑3↓TS)÷86400000
      :EndIf
    ∇

    ∇ TS←IDNToDate SM                ⍝ Convert IDN to date format : 3↑⎕TS ← IDN (akd TS_SM)
      TS←3↑2 ⎕NQ'.' 'IDNToDate'(⌊SM)
      TS,←⌊0.5+24 60 60 1000⊤86400000×1|SM
    ∇

    ∇ new←ts IdnAdd t
    ⍝ T is D HH MM SS
      new←ts+(0 24 60 60 1000⊥¯5↑t,0)÷86400000
    ∇

    ∇ r←Now
      r←DateToIDN ⎕TS
    ∇

    ∇ r←TSFmt ts
      r←,'ZI4,<->,ZI2,<->,ZI2,< >,ZI2,<:>,ZI2,<:>,ZI2'⎕FMT 1 6⍴6↑ts
    ∇

    ∇ r←TSFmtNice ts;now;yday;today;z;i;m;idn;s
    ⍝ Format a vector of IDN's nicely
      s←⍴ts
      yday←¯1+today←⌊now←DateToIDN ⎕TS
      r←↑IDNToDate¨,ts←,ts ⍝ Make matrix
      r←'ZI4,<->,ZI2,<->,ZI2,< >,ZI2,<:>,ZI2'⎕FMT 5↑[2]r
      :If 0≠⍴i←((ts≥yday)∧~m←ts≥today)/⍳⍴ts
          r[i;]←r[i;11+⍳5],' ',((⍴i),10)⍴10↑'Yesterday'
      :EndIf
      :If 0≠⍴i←m/⍳⍴ts
          r[i;]←r[i;11+⍳5],' ',((⍴i),10)⍴10↑'Today'
      :EndIf
      :If 0≠⍴i←(100>z←⌊(now-ts)×24×60)/⍳⍴ts
          r[i;]←16↑[2]↑(⍕¨⌊z[i]),¨(' minutes ago' ' minute ago')[1+1=z[i]]
      :EndIf
      :If 0≠⍴i←(z<1)/⍳⍴ts
          r[i;]←((⍴i),16)⍴16↑'Now'
      :EndIf
      r←(s,¯1↑⍴r)⍴r
    ∇

    ∇ r←WeekDay Date
    ⍝ Return weekday (Monday=1, Sunday=7)
      r←1+7|(DateToIDN 3↑Date)-1
    ∇

    ∇ r←{opt}DateFormat ymd
    ⍝ opt - 0 dd MMM yyyy
    ⍝       1 dd Month yyyy
      :If 0=⎕NC'opt' ⋄ opt←0 ⋄ :EndIf
      :Select ⊃opt
      :Case 0
          r←(⍕ymd[3]),(1⌽'  ',3↑(3×¯1+ymd[2])↓'JANFEBMARAPRMAYJUNJULAUGSEPOCTNOVDEC'),⍕ymd[1]
      :Case 1
          r←(⍕ymd[3]),(1⌽'  ',ymd[2]⊃'January' 'February' 'March' 'April' 'May' 'June' 'July' 'August' 'September' 'October' 'November' 'December'),⍕ymd[1]
      :Else
          r←⍕ymd
      :EndSelect
    ∇

    ∇ r←LogFmtNow;ver
    ⍝ returns now UTC adjusted, and formatted for log files (Common Log Format)
      :If 'Win'≡ver←3↑1⊃'.'⎕WG'APLVersion'
          r←((⍎⎕NA'kernel32|GetSystemTime >{U2 U2 U2 U2 U2 U2 U2 U2}')⊂8⍴0)[4 2 1 5 6 7]
          r[2]←⊂(12 3⍴'JanFebMarAprMayJunJulAugSepOctNovDec')[,2⊃r;]
          r←,'< [>,ZI2,</>,3A1,</>,ZI4,<:>,ZI2,<:>,ZI2,<:>,ZI2,< +0000] >'⎕FMT r
      :Else
          r←1⊃⎕SH'date +" [%d/%b/%Y:%T %z] "'
      :EndIf
    ∇

    ∇ r←LogFmt ymdhms
      r←ymdhms[3 2 1 4 5 6]
      r[2]←⊂(12 3⍴'JanFebMarAprMayJunJulAugSepOctNovDec')[,2⊃r;]
      r←,'< [>,ZI2,</>,3A1,</>,ZI4,<:>,ZI2,<:>,ZI2,<:>,ZI2,< +0000] >'⎕FMT r
    ∇

    ∇ ts←FTT fts;md;shape;tmp;yr;z;⎕IO
     ⍝ *** convert ⎕FRDCI/⎕FHIST timestamp(s) to ⎕ts-format for Dyalog/W ***
     ⍝ right argument: ⎕FRDCI-type timestamp(s) of any shape
     ⍝ result: ⎕ts-type timestamp(s) with shape <(⍴argument),7>
      ⎕IO←0 ⋄ shape←⍴fts ⋄ ts←,fts+18626112000
      md←365.2501|1+1461|yr←⌊ts÷5184000
      tmp←31 61 92 122 153 184 214 245 275 306 337 366
      z←(,⍉<⍀tmp∘.≥md)/,((⍴md),12)⍴⍳12
      md←(1+12|z+2),[0.1]⌈md-(0,tmp)[z]
      ts←(1960+⌊(yr+60)÷365.25),md,⍉24 60 60 60⊤ts
      ts[;6]←⌊0.5+ts[;6]×100÷6
      ts←(shape,7)⍴ts
    ∇

    ∇ r←TTF ts;l;h;d;m;y
       ⍝ convert a ⎕TS style timestamp into 60ths of a second since 1st January 1970 a la ⎕FRDCI
      l←⌈60×ts[7]÷1000                                         ⍝ convert milliseconds to 60ths
      h←3600 60 60⊥ts[4 5 6]                                   ⍝ hours minutes seconds to to the nearest seconds total
      d←ts[3]-1                                                ⍝ days since start of month
      m←(2⊃ts)⊃++\0 31,(28+0=4|⊃ts),31 30 31 30 31 31 30 31 30 ⍝ days in completed months
      y←{{(365×⍵)+⌈4÷⍨⍵-2}⍵-1970}⊃ts                           ⍝ days in years since 1970, leap years since 1972
      r←l+60×h+86400×y+m+d                                     ⍝ sum, convert to seconds, add seconds in the day convert to 60ths, add on 60ths
    ∇

    tonum←{(b v)←⎕vfi ⍵ ⋄ b/v}

    ∇ dt←ParseDate str;pos;mon;t;ymd
     ⍝ str is of the genre "Wed Aug 05 2015 07:30:21 GMT-0400 (Eastern Daylight Time)"
     ⍝ We need to weed out the day of the week and the time
      str←(+/∧\' '=str)↓str           ⍝ remove the leading spaces
     ⍝ What kind of string is this?
      :If ~∧/1⊃(dt dt)←{b←~⍵∊'/-:' ⋄ ⎕VFI b\b/⍵}str  ⍝ yyyy/mm/dd hh:mm:ss ?
          :If 0∊⍴t←'Jan' 'Feb' 'Mar' 'Apr' 'May' 'Jun' 'Jul' 'Aug' 'Sep' 'Oct' 'Nov' 'Dec'⎕S 0 3⊢str      ⍝ look for the month as a string. If not found
              ymd←3↑tonum str                ⍝ grab the 1st 3 numbers found
              ymd←ymd[⍒(2×31<ymd)+ymd<12] ⍝ put in correct order
          :Else                           ⍝ otherwise (if found)
              (pos mon)←0 1+1⊃t
              :If ~0∊⍴t←tonum pos↑str        ⍝ any number before the month? (e.g. 2 May 2021)
                  ymd←⌽⍣(31<⍬⍴t)⊢(1↑tonum pos↓str),mon,t
              :Else
                  ymd←¯1⌽mon,2↑tonum pos↓str
              :EndIf
          :EndIf
     ⍝ Now grab the time
          dt←ymd,tonum⍕'(\d+):(\d+):(\d+)'⎕S'\1 \2 \3'⊢str
      :EndIf
    ∇

    ∇ ts←ParseISODate str
      SetUtcOffset
      ts←IDNToDate(-_UtcOffset÷24×60)+DateToIDN 7↑str{⊃(//)⎕VFI ⍵\⍵/⍺}str∊⎕D
    ∇

    ∇ r←{unit}ParseTime string;chunks;units;factors
     ⍝ Parse time string into units (default is ms)
     ⍝ String is a string like '5d4h47m6s266ms'
      :If 0=⎕NC'unit' ⋄ unit←'ms' ⋄ :EndIf
      units←(1 1 1 1 1 0⊂'dhmsms'),⊂''
      factors←86400000 3600000 60000 1000 1 1
      chunks←{⍵⊆⍨1+⍵∊⎕D},string
      :Trap 0/0
          r←(⍎¨{⍵∩⎕D}¨chunks)+.×factors[units⍳{#.Strings.lc ⍵~⎕D}¨chunks]
      :Else
          'Invalid time string'⎕SIGNAL 11
      :EndTrap
      r←r÷factors[units⍳⊂,unit]
    ∇

:EndNamespace

Make Dates.ParseTime work with scalar argument


 output←regexes(op Run args)input;from;to;options;lines;trans;Expand;repeat;s;r

 :Trap 11 22 ⍝ accept filename or actual input
     input←input ⎕NTIE 0
 :EndTrap

 :Trap 11 22 ⍝ accept filename or actual regex
     regexes←⊃⎕NGET regexes 1
 :EndTrap

 repeat←⍎{×≢⍵:⍵ ⋄ '1'}args∩'≡',⎕D ⍝ extract repetition, if any, else 1
 ⍝ select options:
 options←('ResultText' 'Simple')('Greedy' 0)('IC' 1)('Mode' 'D')('Mode' 'M')('DotAll' '1')('UCP' 1)('OM' 1)/⍨1,'gidmauo'∊819⌶args~' -'
 s r←(∨/∊∘op)¨'Ss' 'Rr'
 options↓⍨←s ⍝ ResultText is not for ⎕S

 :If 2|≢regexes ⍝ odd number of strings → many-to-one
 :OrIf '⍵'∊⊃⌽regexes ⍝ transformation function → many-to-function
     from←¯1↓regexes ⍝ remove transformation pattern/function
     :If ~'⍵'∊⊃⌽regexes ⍝ no ⍵ → pattern
         Expand←'⍵B' '⍵b' '⍵P' '⍵p' '⍵M' '⍵O' '⍵L' '⍵N'⎕R'⍵.Block' '⍵.BlockNum' '⍵.Pattern' '⍵.PatternNum' '⍵.Match' '⍵.Offsets' '⍵.Lengths' '⍵.Names'
     :OrIf ~≡⎕FX('to←{',(r/',⍕'),'{')(Expand⊃⌽regexes)'}⍵}' ⍝ if definition fails, revert to pattern (allows ⍵ in pattern)
         to←⊃⌽regexes
     :EndIf
 :Else
     lines←2÷⍨≢regexes
     from←lines↑regexes
     to←lines↓regexes
 :EndIf

 :If r
     output←from ⎕R to⍠options⍣repeat⊢input
 :ElseIf s
     output←from ⎕S to⍠options⍣repeat⊢input
     output←{⊃,/⍵↑¨⍨⌈/≢¨⍵}⍣(∨/args∊⍨'≡',⎕D)⊢output ⍝ merge search results if we need to continue
 :Else
     'Left operand must be ''R'' or ''S'''⎕SIGNAL 11
 :EndIf

 output←regexes(op Run args)input;from;to;options;lines;trans;Expand;repeat;s;r;last;fns;Quote;q;hasrepeat;postproc;combine

 :Trap 11 22 ⍝ accept filename or actual input
     input←input ⎕NTIE 0
 :EndTrap

 :Trap 11 22 ⍝ accept filename or actual regex
     regexes←⊃⎕NGET regexes 1
 :EndTrap

 repeat←⍎{×≢⍵:⍵ ⋄ '1'}args∩'≡',⎕D ⍝ extract repetition, if any, else 1
 hasrepeat←∨/args∊⍨'≡',⎕D
 ⍝ select options:
 options←('ResultText' 'Simple')('Greedy' 0)('IC' 1)('Mode' 'D')('Mode' 'M')('DotAll' '1')('UCP' 1)('OM' 1)/⍨1,'gidmauo'∊819⌶args~' -'
 s r←(∨/∊∘op)¨'Ss' 'Rr'
 options↓⍨←s ⍝ ResultText is not for ⎕S

 fns←+/∧\'⍵'∊¨regexes
 postproc←∊'{⍵}','∘{'∘,¨,∘'}'¨fns↑regexes ⍝ post-processing functions
 regexes↓⍨←fns

 last←⊃⌽regexes
 :If 2|≢regexes ⍝ odd number of strings → many-to-one
 :OrIf '⍵'∊last ⍝ transformation function → many-to-function
     from←¯1↓regexes ⍝ remove transformation pattern/function
     :If ~'⍵'∊last ⍝ no ⍵ → pattern
         Expand←'⍵B' '⍵b' '⍵P' '⍵p' '⍵M' '⍵O' '⍵L' '⍵N'⎕R'⍵.Block' '⍵.BlockNum' '⍵.Pattern' '⍵.PatternNum' '⍵.Match' '⍵.Offsets' '⍵.Lengths' '⍵.Names'
     :OrIf ~≡⎕FX'to←{'(r/',⍕{')(Expand last)(r/'}⍵')'}' ⍝ if definition fails, revert to pattern (allows ⍵ in pattern)
         to←⊃⌽regexes
     :EndIf
 :Else
     lines←2÷⍨≢regexes
     from←lines↑regexes
     to←lines↓regexes
 :EndIf

 combine←'{⊃,/⍵↑¨⍨⌈/≢¨⍵}'
 q←⎕NS ⍬
 :If s r∨.∧'?'∊args
     Quote←{q,q,⍨⍵/⍨1+⍵=q←''''}
     q.from←⍕Quote¨from
     :If 3=⎕NC'to'
         q.to←1⌽'  ',3↓∊⎕NR'to'
     :Else
         q.to←⍕Quote¨to
     :EndIf
     :If 3=⎕NC'repeat'
         q.repeat←'⍣',∊⎕NR'repeat'
     :ElseIf 1≢repeat
         q.repeat←'⍣',⍕repeat
     :Else
         q.repeat←''
     :EndIf
     q.op←s r/'SR'
     q.postproc←4↓postproc
     q.postproc,←(hasrepeat∧s)/(''≡q.postproc)↓'∘',combine
     output←q.(postproc,from,'⎕',op,to,repeat)
 :Else
     :Trap 6 11
         :If r
             output←from ⎕R to⍠options⍣repeat⊢input
         :ElseIf s
             output←from ⎕S to⍠options⍣repeat⊢input
             output←(⍎combine)⍣hasrepeat⊢output ⍝ merge search results if we need to continue
         :EndIf
         output←(⍎postproc)output
     :Case 6 ⍝ no output
         output←'*** Left operand must be ''R'' or ''S'' ***'
     :Case 11 ⍝ faulty regex
         output←'*** ',⎕DMX.Message,' ─ try adding ? to the Arguments to see the attempted APL expression ***'
     :EndTrap
 :EndIf

Allow postproc functions. Accept ? to display APL expression. Proper error messages.


 output←regexes(op Run args)input;from;to;options;lines;trans;Expand;repeat;s;r

 :Trap 11 22 ⍝ accept filename or actual input
     input←input ⎕NTIE 0
 :EndTrap

 :Trap 11 22 ⍝ accept filename or actual regex
     regexes←⊃⎕NGET regexes 1
 :EndTrap

 repeat←⍎{×≢⍵:⍵ ⋄ '1'}args∩'≡',⎕D ⍝ extract repetition, if any, else 1
 ⍝ select options:
 options←('ResultText' 'Simple')('Greedy' 0)('IC' 1)('Mode' 'D')('Mode' 'M')('DotAll' '1')('UCP' 1)('OM' 1)/⍨1,'gidmauo'∊819⌶args~' -'
 s r←(∨/∊∘'sabcA')¨'Ss' 'Rr'
 options↓⍨←s ⍝ ResultText is not for ⎕S

 :If 2|≢regexes ⍝ odd number of strings → many-to-one
 :OrIf '⍵'∊⊃⌽regexes ⍝ transformation function → many-to-function
     from←¯1↓regexes ⍝ remove transformation pattern/function
     :If ~'⍵'∊⊃⌽regexes ⍝ no ⍵ → pattern
         Expand←'⍵B' '⍵b' '⍵P' '⍵p' '⍵M' '⍵O' '⍵L' '⍵N'⎕R'⍵.Block' '⍵.BlockNum' '⍵.Pattern' '⍵.PatternNum' '⍵.Match' '⍵.Offsets' '⍵.Lengths' '⍵.Names'
     :OrIf ~≡⎕FX('to←{',(r/',⍕'),'{')(Expand⊃⌽regexes)'}⍵}' ⍝ if definition fails, revert to pattern (allows ⍵ in pattern)
         to←⊃⌽regexes
     :EndIf
 :Else
     lines←2÷⍨≢regexes
     from←lines↑regexes
     to←lines↓regexes
 :EndIf

 :If r
     output←from ⎕R to⍠options⍣repeat⊢input
 :ElseIf s
     output←from ⎕S to⍠options⍣repeat⊢input
     output←{⊃,/⍵↑¨⍨⌈/≢¨⍵}⍣(∨/args∊⍨'≡',⎕D)⊢output ⍝ merge search results if we need to continue
 :Else
     'Left operand must be ''R'' or ''S'''⎕SIGNAL 11
 :EndIf

 output←regexes(op Run args)input;from;to;options;lines;trans;Expand;repeat;s;r

 :Trap 11 22 ⍝ accept filename or actual input
     input←input ⎕NTIE 0
 :EndTrap

 :Trap 11 22 ⍝ accept filename or actual regex
     regexes←⊃⎕NGET regexes 1
 :EndTrap

 repeat←⍎{×≢⍵:⍵ ⋄ '1'}args∩'≡',⎕D ⍝ extract repetition, if any, else 1
 ⍝ select options:
 options←('ResultText' 'Simple')('Greedy' 0)('IC' 1)('Mode' 'D')('Mode' 'M')('DotAll' '1')('UCP' 1)('OM' 1)/⍨1,'gidmauo'∊819⌶args~' -'
 s r←(∨/∊∘op)¨'Ss' 'Rr'
 options↓⍨←s ⍝ ResultText is not for ⎕S

 :If 2|≢regexes ⍝ odd number of strings → many-to-one
 :OrIf '⍵'∊⊃⌽regexes ⍝ transformation function → many-to-function
     from←¯1↓regexes ⍝ remove transformation pattern/function
     :If ~'⍵'∊⊃⌽regexes ⍝ no ⍵ → pattern
         Expand←'⍵B' '⍵b' '⍵P' '⍵p' '⍵M' '⍵O' '⍵L' '⍵N'⎕R'⍵.Block' '⍵.BlockNum' '⍵.Pattern' '⍵.PatternNum' '⍵.Match' '⍵.Offsets' '⍵.Lengths' '⍵.Names'
     :OrIf ~≡⎕FX('to←{',(r/',⍕'),'{')(Expand⊃⌽regexes)'}⍵}' ⍝ if definition fails, revert to pattern (allows ⍵ in pattern)
         to←⊃⌽regexes
     :EndIf
 :Else
     lines←2÷⍨≢regexes
     from←lines↑regexes
     to←lines↓regexes
 :EndIf

 :If r
     output←from ⎕R to⍠options⍣repeat⊢input
 :ElseIf s
     output←from ⎕S to⍠options⍣repeat⊢input
     output←{⊃,/⍵↑¨⍨⌈/≢¨⍵}⍣(∨/args∊⍨'≡',⎕D)⊢output ⍝ merge search results if we need to continue
 :Else
     'Left operand must be ''R'' or ''S'''⎕SIGNAL 11
 :EndIf

Replace dummy string with actual variable name


:Class WidgetDoc : MiPageTemplate

    ∇ Compose;ns;widget;doc
      :Access public
      (ns widget)←Get'namespace widget'
      Add _.StyleSheet'/Styles/widgetDoc.css'
      doc←ns Document widget
      :Select doc
      :Case ¯1
          (Add _.h3('Namespace "',ns,'" not found.')).Style'color' 'red'
      :Case ¯2
          (Add _.h3('Widget "',widget,'" not found in namespace ',ns)).Style'color' 'red'
      :Else
          Add _.h3 ns,'.',widget
          :If 0∊⍴doc
              Add _.h4'No documentation found.'
          :Else
              doc[;2]←{New _.pre ⍵}¨doc[;2]
              (Add #._.Table doc).CellAttr←'class="widgetDoc"' 'class="widgetDocContent"'
          :EndIf
      :EndSelect
    ∇

    ∇ r←ns Document widget;ref;wref;src;mask;chunk;pv;c;c1;c2;samples;files
      :Access public shared
      r←¯1
      :If 9.1=#.⎕NC⊂ns
          ref←#.⍎ns
          r←¯2
          :If 9=ref.⎕NC widget
              wref←ref⍎widget
              src←1↓⎕SRC wref
              src↓⍨←+/∧\''∘≡¨src
              src←#.Strings.dlb¨src
              src←src/⍨∧\'⍝'=⊃¨src
              src←HtmlSafeText¨#.Strings.dlb¨1↓¨src
              pv←∨/¨'::'∘⍷¨src
              r←0 2⍴⊂''
              :For chunk :In pv⊂src
                  c←⊃chunk
                  (c1 c2)←{⍵{(1,1↓<\⍵)⊂⍺}'::'⍷⍵}c
                  c2←#.Strings.deb 2↓c2
                  c2←c2{0∊⍴⍺:⍵ ⋄ 0∊⍴⍵:⊂⍺ ⋄ (⊂⍺),⍵}1↓chunk
                  c2←¯2↓∊c2,¨⊂⎕UCS 13 10
                  r⍪←c1 c2
              :EndFor
              :If 0≠wref.⎕NC⊂'DocBase'
                  r⍪←'Documentation'('target=_blank'New _.A(2⍴⊂wref.DocBase))
              :EndIf
              samples←'/Examples/',(ns~'_'),'/'
              :If ~0∊⍴files←1⌷[2]#.Files.List #.Boot.ms.Config.AppRoot,samples
                  files/⍨←∨/files∘.#.Strings.(beginsWith nocase)widget∘,¨'Simp' 'Adv'
              :AndIf ~0∊⍴files
                  r⍪←'Sample Pages'({'target=_blank'New _.A(2⍴⊂⍵)}¨samples∘,¨files)
              :EndIf
          :EndIf
      :EndIf
    ∇

:EndClass

:Class WidgetDoc : MiPageTemplate

    ∇ Compose;ns;widget;doc;t;opts;og
      :Access public
      Add _.StyleSheet'/Styles/widgetDoc.css'
      (ns widget)←Get'namespace widget'
      :If 0∊⍴widget
          Add _.h3'Select widget'
          opts←'onchange="window.open(this.value,''this'');this.selectedIndex=0"'Add _.select
          'disabled=' 'value='opts.Add _.option'[Select widget]'
          :For ns :In '_DC' '_SF' '_JQ' '_html'
              og←('label'ns)opts.Add _.optgroup
              :For widget :In (⍎ns).⎕NL ¯9
                  ('value=?namespace=',ns,'&widget=',widget)og.Add _.option widget
              :EndFor
          :EndFor
      :Else
          doc←ns Document widget
          doc[;2]←{New _.pre ⍵}¨doc[;2]
          Add _.h3 ns,'.',widget
          (Add #._.Table doc).CellAttr←'class="widgetDoc"' 'class="widgetDocContent"'
      :EndIf
    ∇

    ∇ r←ns Document widget;ref;wref;src;mask;chunk;pv;c;c1;c2;samples;files
      :Access public shared
      r←''
      :If 9.1=#.⎕NC⊂ns
          ref←#.⍎ns
          :If 9=ref.⎕NC widget
              wref←ref⍎widget
              src←1↓⎕SRC wref
              src↓⍨←+/∧\''∘≡¨src
              src←#.Strings.dlb¨src
              src←src/⍨∧\'⍝'=⊃¨src
              src←HtmlSafeText¨#.Strings.dlb¨1↓¨src
              pv←∨/¨'::'∘⍷¨src
              r←0 2⍴⊂''
              :For chunk :In pv⊂src
                  c←⊃chunk
                  (c1 c2)←{⍵{(1,1↓<\⍵)⊂⍺}'::'⍷⍵}c
                  c2←#.Strings.deb 2↓c2
                  c2←c2{0∊⍴⍺:⍵ ⋄ 0∊⍴⍵:⊂⍺ ⋄ (⊂⍺),⍵}1↓chunk
                  c2←¯2↓∊c2,¨⊂⎕UCS 13 10
                  r⍪←c1 c2
              :EndFor
              :If 0≠wref.⎕NC⊂'DocBase'
                  r⍪←'Documentation'('target=_blank'New _.A(2⍴⊂wref.DocBase))
              :EndIf
              samples←'/Examples/',(ns~'_'),'/'
              :If ~0∊⍴files←1⌷[2]#.Files.List #.Boot.ms.Config.AppRoot,samples
              :AndIf ~0∊⍴files/⍨←∨/files∘.#.Strings.(beginsWith nocase)widget∘,¨'Simp' 'Adv'
                  r⍪←'Sample Pages'({'target=_blank'New _.A(2⍴⊂⍵)}¨samples∘,¨files)
              :EndIf
          :EndIf
      :EndIf
    ∇

:EndClass

Resolve conflict

Resolve conflict


:Class Logger ⍝ Logs HTTP requests

    ⎕ML←1

    :field public instance Active←0
    :field private instance Directory←''
    :field private instance Interval←10  ⍝ write cache interval in seconds
    :field private instance TieNo←⍬
    :field private instance Cache←''
    :field private instance Prefix←''
    :field private instance tid←¯1
    :field private EOL                  ⍝ End Of Line

    missing←{0∊⍴⍵:'-' ⋄ ⍵}

    ∇ Make ms;file;log
      :Access public
      :Implements Constructor
      ⍝ load logger information
      Active←0
      EOL←⎕UCS 13 10↓⍨~#.Boot.isWin
      :If #.Files.Exists file←ms.Config.Root,'Config/Logger.xml'
      :AndIf ~0∊⍴log←(#.XML.ToNS #.Files.ReadText file).Logger
          Active←log #.Boot.Setting'active' 1 0
          Prefix←log #.Boot.Setting'prefix' 0 ''
          Interval←log #.Boot.Setting'interval' 1 10
          Directory←#.Boot.SubstPath log #.Boot.Setting'directory' 0 ''
          Directory,←(~'/\'∊⍨¯1↑Directory)/'/'
          ('Log file directory "',Directory,'" not found!')⎕SIGNAL 11/⍨~#.Files.DirExists Directory
      :EndIf
      :If Active
          tid←Run&0
      :EndIf
    ∇

    ∇ UnMake
      :Implements destructor
      Stop ⍬
    ∇

    ∇ Stop w
      :Access public
      :Trap 0
          :If Active
              Active←0
              ⎕TKILL tid
              :If Open
                  ClearCache
                  Close
              :EndIf
          :EndIf
      :EndTrap
    ∇

    ∇ Start
      :Access public
      :If ~tid∊⎕TNUMS
          Active←1
          tid←Run&0
      :EndIf
    ∇

    ∇ Run x;done
      :While Active
          {}⎕DL Interval
          :If Open
              ClearCache
              Close
          :EndIf
      :EndWhile
    ∇

    ∇ r←Open;fn
      r←0
      :Trap 6
          fn←#.Files.Normalize Directory,Prefix,(⍕100⊥3↑⎕TS),'.log'
      :Else
          →0
      :EndTrap

      :Trap 22 ⍝ file name error
          TieNo←fn ⎕NTIE 0 34
      :Else
          :Trap 0
              ⎕NUNTIE fn ⎕NCREATE 0
              TieNo←fn ⎕NTIE 0 34
          :Else
              1 ##.ms.Log'Unable to open log file "',fn,'"'
              :Return
          :EndTrap
      :EndTrap
      r←0≠TieNo
    ∇

    ∇ Log req
      :Access public
      :If Active
          :Hold 'Lumberjack'
              Cache,←((missing 2⊃req.PeerAddr),' ',(missing req.Session.User),#.Dates.LogFmtNow,'"',req.Method,' ',req.Page,'"',∊' '∘,∘⍕¨req.Response.(Status MSec Bytes)),EOL
          :EndHold
      :EndIf
    ∇

    ∇ ClearCache
      :Hold 'Lumberjack'
          Cache ⎕NAPPEND TieNo
          Cache←''
      :EndHold
    ∇

    ∇ Close
      ⎕NUNTIE TieNo
    ∇
:EndClass

:Class Logger ⍝ Logs HTTP requests

    ⎕ML←1

    :field public instance Active←0
    :field private instance Directory←''
    :field private instance Interval←10  ⍝ write cache interval in seconds
    :field private instance TieNo←⍬
    :field private instance Cache←''
    :field private instance Prefix←''
    :field private instance tid←¯1
    :field private EOL                  ⍝ End Of Line

    missing←{0∊⍴⍵:'-' ⋄ ⍵}

    ∇ Make ms;file;log
      :Access public
      :Implements Constructor
      ⍝ load logger information
      Active←0
      EOL←⎕UCS 13 10↓⍨~#.Boot.isWin
      :If #.Files.Exists file←ms.Config.Root,'Config/Logger.xml'
      :AndIf ~0∊⍴log←(#.XML.ToNS #.Files.ReadText file).Logger
          Active←log #.Boot.Setting'active' 1 0
          Prefix←log #.Boot.Setting'prefix' 0 ''
          Interval←log #.Boot.Setting'interval' 1 10
          Directory←#.Boot.SubstPath log #.Boot.Setting'directory' 0 ''
          Directory,←(~'/\'∊⍨¯1↑Directory)/'/'
          ('Log file directory "',Directory,'" not found!')⎕SIGNAL 11/⍨~#.Files.DirExists Directory
      :EndIf
      :If Active
          tid←Run&0
      :EndIf
    ∇

    ∇ UnMake
      :Implements destructor
      Stop ⍬
    ∇

    ∇ Stop w
      :Access public
      :Trap 0
          :If Active
              Active←0
              ⎕TKILL tid
              :If Open
                  ClearCache
                  Close
              :EndIf
          :EndIf
      :EndTrap
    ∇

    ∇ Start
      :Access public
      :If ~tid∊⎕TNUMS
          Active←1
          tid←Run&0
      :EndIf
    ∇

    ∇ Run x;done
      :While Active
          {}⎕DL Interval
          :If Open
              ClearCache
              Close
          :EndIf
      :EndWhile
    ∇

    ∇ r←Open;fn
      r←0
      :Trap 6
          fn←#.Files.Normalize Directory,Prefix,(⍕100⊥3↑⎕TS),'.log'
      :Else
          →0
      :EndTrap

      :Trap 22 ⍝ file name error
          TieNo←fn ⎕NTIE 0 34
      :Else
          :Trap 0
              ⎕NUNTIE fn ⎕NCREATE 0
              TieNo←fn ⎕NTIE 0 34
          :Else
              1 ##.ms.Log'Unable to open log file "',fn,'"'
              :Return
          :EndTrap
      :EndTrap
      r←0≠TieNo
    ∇

    tryGetting←{0::('-'@(' '∘=))(⊃⎕DM),'-retrieving-"',⍵,'"' ⋄ ⍕⍎⍵}

    ∇ Log req;addr;user;ts;method;page;status;msec;bytes
      :Access public
      :If Active
          :Hold 'Lumberjack'
              :Trap 0
                  Cache,←((missing 2⊃req.PeerAddr),' ',(missing req.Session.User),#.Dates.LogFmtNow,'"',req.Method,' ',req.Page,'"',∊' '∘,∘⍕¨req.Response.(Status MSec Bytes)),EOL
              :Else ⍝ something in logging failed, try figuring out what
                  addr←tryGetting'req.PeerAddr'
                  user←tryGetting'req.Session.User'
                  ts←tryGetting'#.Dates.LogFmtNow'
                  method←tryGetting'req.Method'
                  page←tryGetting'req.Page'
                  status←tryGetting'req.Response.Status'
                  msec←tryGetting'req.Response.MSec'
                  bytes←tryGetting'req.Response.Bytes'
                  Cache,←(missing addr),' ',(missing user),ts,'"',method,' ',page,'" ',status,' ',msec,' ',bytes,EOL
              :EndTrap
          :EndHold
      :EndIf
    ∇

    ∇ ClearCache
      :Hold 'Lumberjack'
          Cache ⎕NAPPEND TieNo
          Cache←''
      :EndHold
    ∇

    ∇ Close
      ⎕NUNTIE TieNo
    ∇
:EndClass

Add debugging information to Logger.Log

Add debugging information to Logger.Log


:Class MiPageSample : #.MiPage
   ⍝ This is a template that "wraps" the page content by
   ⍝ - adding a header and footer
   ⍝ - adding a handler that will toggle the display of the web page and its APL source code

    ∇ {r}←Wrap;lang;server;src;c
      :Access Public

      :If 0∊⍴Get'nowrapper'
          server←_Request.Server

        ⍝ we need jQuery to toggle content/source, other resources will be loaded if needed
          Use'JQuery' ⍝ this is a resource defined in Config/Resources.xml

        ⍝ set the title display in the browser to the name of the page or application
          Add _.title('Advanced' 'Simple' 'Examples?' 'index' '_'⎕R'' '' ''server.Config.Name' '((-'.'⍳⍨⌽)↓⊢↑⍨1-'/'⍳⍨⌽)_Request.Page)

        ⍝ add a link to our CSS stylesheet
          _CssReset←'/Styles/cssreset.css'
          _CssOverride←'/Styles/sampleStyles.css'

        ⍝ set a meta tag to make it explicitly UTF-8
        ⍝  (Add _.meta).Set'http-equiv="content-type" content="text/html;charset=UTF-8"'

        ⍝ wrap the content of the  element in a div
          'contentblock'Body.Push _.div

        ⍝ add a hidden division to the body containing the APL source code
          (Add _.div(#.HtmlUtils.APLToHTMLColor src←⎕SRC⊃⊃⎕CLASS ⎕THIS)).Set'id="codeblock"' 'style="display: none;"'

        ⍝ extract the content and re-write it in parallel to the controls info div
          c←Body.Content
          Body.Content←''
          Body.Add c

        ⍝ create a division with info about the controls used
          Body.Add CtrlsDiv src

        ⍝ wrap the content of the  element in a div
          '.bodyblock'Body.Push _.div

        ⍝ add the header to the top of the page and wrap the body in a div with id="wrapper"
          Body.Push #.Files.ReadText server.Config.Root,'Styles/banner.txt'

          'wrapper'Body.Push _.div

        ⍝ add a JQuery event handler to toggle the web page/APL source code
          Add _.Script ScriptFollows
          ⍝ $(function(){
          ⍝   $("#tocode").click(function(){
          ⍝     $("#contentblock").hide();
          ⍝     $("#codeblock").show();
          ⍝     $("#widgethelp").addClass("sliddown");
          ⍝     $("#topage").removeClass("activetab");
          ⍝     $("#tocode").addClass("activetab");
          ⍝   });
          ⍝   $("#topage").click(function(){
          ⍝     $("#contentblock").show();
          ⍝     $("#codeblock").hide();
          ⍝     $("#widgethelp").removeClass("sliddown");
          ⍝     $("#topage").addClass("activetab");
          ⍝     $("#tocode").removeClass("activetab");
          ⍝   });
          ⍝ });

      :Else
          Head.Add _.StyleSheet'/Styles/sampleStyles.css'
          Body.class←'bodyblock'
      :EndIf
     ⍝ call the base class Wrap function

      r←⎕BASE.Wrap
    ∇

    ∇ r←CtrlsDiv source;control;controls;ns;pattern
     ⍝ Creates a div with info on the controls used in source

     ⍝ First we extract proper lists of controls
      controls←(⍴#.MS3SiteUtils.NSS)/⊂''
      source←(⍳∘'⍝'↑⊢)¨source      ⍝ remove comments
      source←{⍵/⍨~≠\''''=⍵}¨source ⍝ remove strings but leaves one ' as separator
      pattern←8⌽')\.(\w+)_(',∊#.MS3SiteUtils.NSS,¨'|'
      :For control :In 'Handler' 'Position'~⍨∪(pattern⎕S'\2')source ⍝ find controls
          :Trap 6 ⍝ unknown
              ns←(#.MS3SiteUtils.NSS(∨/⍷)¨⊂⍕⍎'#._.',control)/⍳⍴#.MS3SiteUtils.NSS ⍝ add to right list
          :Else
              ns←⍬
          :EndTrap
          controls[ns],←⊂⊂control
      :EndFor
      controls←{⍵[⍋↑⍵]}¨controls   ⍝ sort the lists

     ⍝ Now we create and populate the info div
      r←'
Controls used on this page:'
      :For ns :In (×≢¨controls)/⍳⍴#.MS3SiteUtils.NSS ⍝ do not process if empty
          r,←' ',(ns⊃#.MS3SiteUtils.GROUPS),': '
          :For control :In ns⊃controls
              r,←'',control,', '
          :EndFor
          r↓⍨←¯7
      :EndFor
      r,←'
'
    ∇

    ∇ r←Walk content;e
      r←⍬
      :For e :In content
          :If (isClass e)∨isInstance e
              r←r,⊃⎕CLASS e
              :Trap 6
                  r,←Walk e.Content
              :EndTrap
          :EndIf
      :EndFor
    ∇

:EndClass

:Class MiPageSample : #.MiPage
   ⍝ This is a template that "wraps" the page content by
   ⍝ - adding a header and footer
   ⍝ - adding a handler that will toggle the display of the web page and its APL source code

    :Field Public _Sessioned←0

    ∇ {r}←Wrap;lang;server;src;c
      :Access Public

      :If 0∊⍴Get'nowrapper'
          server←_Request.Server

        ⍝ we need jQuery to toggle content/source, other resources will be loaded if needed
          Use'JQuery' ⍝ this is a resource defined in Config/Resources.xml

        ⍝ set the title display in the browser to the name of the page or application
          Add _.title('Advanced' 'Simple' 'Examples?' 'index' '_'⎕R'' '' ''server.Config.Name' '((-'.'⍳⍨⌽)↓⊢↑⍨1-'/'⍳⍨⌽)_Request.Page)

        ⍝ add a link to our CSS stylesheet
          _CssReset←'/Styles/cssreset.css'
          _CssOverride←'/Styles/sampleStyles.css'

        ⍝ set a meta tag to make it explicitly UTF-8
        ⍝  (Add _.meta).Set'http-equiv="content-type" content="text/html;charset=UTF-8"'

        ⍝ wrap the content of the  element in a div
          'contentblock'Body.Push _.div

        ⍝ add a hidden division to the body containing the APL source code
          (Add _.div(#.HtmlUtils.APLToHTMLColor src←⎕SRC⊃⊃⎕CLASS ⎕THIS)).Set'id="codeblock"' 'style="display: none;"'

        ⍝ extract the content and re-write it in parallel to the controls info div
          c←Body.Content
          Body.Content←''
          Body.Add c

        ⍝ create a division with info about the controls used
          Body.Add CtrlsDiv src

        ⍝ wrap the content of the  element in a div
          '.bodyblock'Body.Push _.div

        ⍝ add the header to the top of the page and wrap the body in a div with id="wrapper"
          Body.Push #.Files.ReadText server.Config.Root,'Styles/banner.txt'

          'wrapper'Body.Push _.div

        ⍝ add a JQuery event handler to toggle the web page/APL source code
          Add _.Script ScriptFollows
          ⍝ $(function(){
          ⍝   $("#tocode").click(function(){
          ⍝     $("#contentblock").hide();
          ⍝     $("#codeblock").show();
          ⍝     $("#widgethelp").addClass("sliddown");
          ⍝     $("#topage").removeClass("activetab");
          ⍝     $("#tocode").addClass("activetab");
          ⍝   });
          ⍝   $("#topage").click(function(){
          ⍝     $("#contentblock").show();
          ⍝     $("#codeblock").hide();
          ⍝     $("#widgethelp").removeClass("sliddown");
          ⍝     $("#topage").addClass("activetab");
          ⍝     $("#tocode").removeClass("activetab");
          ⍝   });
          ⍝ });

      :Else
          Head.Add _.StyleSheet'/Styles/sampleStyles.css'
          Body.class←'bodyblock'
      :EndIf
     ⍝ call the base class Wrap function

      r←⎕BASE.Wrap
    ∇

    ∇ r←CtrlsDiv source;control;controls;ns;pattern
     ⍝ Creates a div with info on the controls used in source

     ⍝ First we extract proper lists of controls
      controls←(⍴#.MS3SiteUtils.NSS)/⊂''
      source←(⍳∘'⍝'↑⊢)¨source      ⍝ remove comments
      source←{⍵/⍨~≠\''''=⍵}¨source ⍝ remove strings but leaves one ' as separator
      pattern←8⌽')\.(\w+)_(',∊#.MS3SiteUtils.NSS,¨'|'
      :For control :In 'Handler' 'Position'~⍨∪(pattern ⎕S'\2')source ⍝ find controls
          :Trap 6 ⍝ unknown
              ns←(#.MS3SiteUtils.NSS(∨/⍷)¨⊂⍕⍎'#._.',control)/⍳⍴#.MS3SiteUtils.NSS ⍝ add to right list
          :Else
              ns←⍬
          :EndTrap
          controls[ns],←⊂⊂control
      :EndFor
      controls←{⍵[⍋↑⍵]}¨controls   ⍝ sort the lists

     ⍝ Now we create and populate the info div
      r←'
Controls used on this page:'
      :For ns :In (×≢¨controls)/⍳⍴#.MS3SiteUtils.NSS ⍝ do not process if empty
          r,←' ',(ns⊃#.MS3SiteUtils.GROUPS),': '
          :For control :In ns⊃controls
              r,←'',control,', '
          :EndFor
          r↓⍨←¯7
      :EndFor
      r,←'
'
    ∇

    ∇ r←Walk content;e
      r←⍬
      :For e :In content
          :If (isClass e)∨isInstance e
              r←r,⊃⎕CLASS e
              :Trap 6
                  r,←Walk e.Content
              :EndTrap
          :EndIf
      :EndFor
    ∇

:EndClass

Make MS3 site page unsessioned

Make MS3 site page unsessioned