Increase your software development productivity 100x

Get more work done, for less effort!

The above might sound like an exaggeration. However, it is not! Simply because in Phosphorus Five, you can reuse almost everything you do. In the video below, I am demonstrating reducing my projects from 388 LOC (Lines Of Code) to 1 LOC, by creating a reusable extension widget, from an existing web app page.

Basically, what this implies, is that you can reuse almost everything you do in one project, to the next. This suggests that if you’re creating more than one project, then every time you start out a new project, you’re almost done with it, before you even start!

You can find the code for this below the video. For the record, I had to slightly modify the code below, to avoid angle brackets, etc, since my blog can’t handle angle brackets in code segments, even if I HTML encode them manually … (Darn it WordPress!!)

Now before you check out the code, realise that we started out with a “page”. Then we turned that page into a reusable extension widget, in roughly 5 seconds. The end result, being a reusable component, we can reuse in other projects, or in other pages in the same solution. Please watch the video for an explanation of how we did this.

Features of our GitHub project browser

The video also demonstrates some other pretty nifty features. For instance, we are able to traverse any project from GitHub, without using any of the GitHub APIs. The way this works, is that we are able to treat HTML semantically, and extract parts of the HTML returned by GitHub, by transforming it into a lambda object, to retrieve its actual “data”. Basically, we’re “scraping” GitHub, and semantically extracting parts of their HTML, to semantically “understand” the structure of the project we’re browsing.

This allows us to treat HTML semantically, as “data”, and create an Ajax TreeView, which you can see either in the video above, or the screenshot below. The Ajax TreeView in our little “app”, is basically created by semantically “scrape” the GitHub project website, retrieving the data for the links to download its folders, and its files, allowing us to recursively traverse any GitHub project, by treating their HTML semantically.

In addition, we will automatically parse any Markdown files, and show them in HTML view, and show any code segments in a “syntax highlighter widget”. To do this, we first use the HTTP REST capabilities of P5, which allows us to download files, using any of the HTTP verbs, such as GET, POST, PUT, etc. Notice, this is done on the server. Then we inject the code into a “pre” HTML widget (code files), which is later highlighted using the highlight.js JavaScript library. The Markdown files, are first converted into markdown using the [markdown2html] Active Event from Phosphorus Five, for then to be injected as the content into a “div” widget.

To understand how we do this, take a look at the code at the bottom of this blog.

Our little code snippet, also shows how you can use the System42’s Ajax TreeView, in addition to creating a “datagrid” manually, by creating a table element, wrapping your “grid”. Below is a screenshot of our little app.

Below is the code we ended up with, after having created our extension widget. Evaluate the following code in your System42/Executor.

/*
 * Creates a GitHub folder browser, that will allow the user 
 * to browse and read all files within each folder of a project.
 * Will create one Ajax TreeView mirroring the folder structure of the project, 
 * semantically parsed from the HTML of the project's landing page, in addition
 * to a "datagrid" allowing the user to see all files within currently selected folder,
 * and view its content.
 */
create-event:sys42.samples.git-hub.file-browser
  return
    container
      oninit
        p5.web.include-css-file:"https://highlightjs.org/static/demo/styles/rainbow.css"
        p5.web.include-javascript-file:"https://highlightjs.org/static/highlight.site.pack.js"
      events

        /*
         * Downloads GitHub index page, and returns the URLs for both 
         * the child folders, and the Markdown files.
         * Expects [_arg] being URL of GitHub HTML page to download, and semantically parse.
         * Returns [.files] and [.folders] being collection of source files, 
         * and folders recursively inwards.
         */
        sys42.samples.git-hub._get-files-folders

          /*
           * Checking cache to see if requested folder has already been traversed, 
           * and exists in cache.
           */
          p5.web.cache.get:sys42.samples.git-hub.{0}
            :x:/../*/_arg?value
          if:x:/@p5.web.cache.get/*/*
            return:x:/@p5.web.cache.get/*/*/*

          /*
           * Buffers.
           */
          .folders-tmp
          .files-tmp
          .folders
          .files

          /*
           * Retrieving all "xxx.md" types of files, in addition to all folders.
           */
          p5.http.get:x:/../*/_arg?value
          p5.html.html2lambda:x:/-/**/content?value
          add:x:/@.files-tmp
            src:x:@"/@p5.html.html2lambda/**/svg/*/\@class/=octicon octicon-file-text/././+/**/a/*/\@href"
          add:x:/@.folders-tmp
            src:x:@"/@p5.html.html2lambda/**/svg/*/\@class/=octicon octicon-file-directory/././+/**/a/*/\@href"

          /*
           * Massaging results from above.
           */
          for-each:x:/@.folders-tmp/*
            split:x:/@_dp/#?value
              =:/
            add:x:/@.folders
              src:@"{0}:""{1}{2}"""
                :x:/@split/0/-?name
                :"https://github.com"
                :x:/@_dp/#?value
          for-each:x:/@.files-tmp/*
            split:x:/@_dp/#?value
              =:/
            add:x:/@.files
              src:@"{0}:""{1}{2}"""
                :x:/@split/0/-?name
                :"https://github.com"
                :x:/@_dp/#?value

          /*
           * Returning folders and files to caller, making sure we cache results first.
           */
          add:x:/../*/p5.web.cache.set/*/*/items
            src:x:/@.files|/@.folders
          p5.web.cache.set:sys42.samples.git-hub.{0}
            :x:/../*/_arg?value
            src
              items
          return:x:/@.files|/@.folders

        /*
         * Creates our TreeView bugger.
         * Expects [.folders] being initially treeview root items to create.
         * Will also create the default "files datagrid" after TreeView has been created.
         * Hence, also expects [.files], which it will pass into creation of "files datagrid".
         */
        sys42.samples.git-hub._create-tree-view

          /*
           * Deleting any previously created datagrids, if existing.
           */
          if
            fetch:x:/0/0?value
              widget-exists:git-hub-treeview
            delete-widget:git-hub-treeview

          /*
           * Adding our treeview items.
           */
          split:x:/../*/_arg?value
            =:int:8
          add:x:/../*/create-widget/*/*/*/items/*/*/items
            src:x:/../*/.folders/*
          set:x:/../*/create-widget/**/root?name
            src:x:/@split/1?name

          /*
           * Creating our actual treeview.
           */
          create-widget:git-hub-treeview
            parent:results-wrapper
            class:col-xs-12 col-md-6 prepend-top git-hub-tree
            widgets
              sys42.widgets.tree

                /*
                 * Lambda callback for when an item is selected.
                 * We just simply retrieves files and folders, and create our 
                 * Markdown "files datagrid" here.
                 */
                .on-select
                  sys42.samples.git-hub._get-files-folders:x:/../*/items/*?name
                  add:x:/../*/sys42.samples.git-hub._create-files-grid
                    src:x:/../*/sys42.samples.git-hub._get-files-folders/*/.files
                  sys42.samples.git-hub._create-files-grid:x:/../*/items/*?name

                /*
                 * Lambda callback for retrieving child items.
                 * We retrieve the files and folders, and returns items to caller (TreeView).
                 */
                .on-get-items
                  sys42.samples.git-hub._get-files-folders:x:/../*/_item-id?value
                  add:x:/../*/return/*/items
                    src:x:/@sys42.samples.git-hub._get-files-folders/*/.folders/*
                  return
                    items
                items
                  root:x:/../*/_arg?value
                    items

          /*
           * Making sure we initially select the root tree item, and populate our
           * datagrid with the root Markdown files.
           */
          add:x:/../*/sys42.widgets.tree.select-items/*
            src:@"""{0}"""
              :x:/../*/_arg?value
          sys42.widgets.tree.select-items:git-hub-treeview
            items
          add:x:/../*/sys42.samples.git-hub._create-files-grid
            src:x:/../*/.files
          sys42.samples.git-hub._create-files-grid

        /*
         * Creates the "datagrid" that shows our files.
         * Expects [.files] being collection of files to create our "datagrid" around.
         */
        sys42.samples.git-hub._create-files-grid

          /*
           * Deleting any previously created datagrids, if existing.
           */
          if
            fetch:x:/0/0?value
              widget-exists:git-hub-datagrid
            delete-widget:git-hub-datagrid

          /*
           * "Databinding" our datagrid.
           */
          apply:x:/../*/create-widget/*/*/*/*/tbody/*/widgets
            src:x:/../*/.files/*
            template
              tr
                onclick

                  // Databound above.
                  {_url}:x:?value
                  sys42.samples.git-hub._create-file-view-widget:x:/@_url?value
                  set-widget-property:x:/../*/_event?value
                    class:active
                  p5.web.viewstate.get:sys42.samples.git-hub.active-row
                  if:x:/@p5.web.viewstate.get/*?value
                    and
                      fetch:x:/0/0?value
                        widget-exists:x:/@p5.web.viewstate.get/*?value
                    delete-widget-property:x:/@p5.web.viewstate.get/*?value
                      class
                  p5.web.viewstate.set:sys42.samples.git-hub.active-row
                    src:x:/../*/_event?value
                widgets
                  td
                    {innerValue}:x:?name

          /*
           * Creating our actual datagrid.
           */
          create-widget:git-hub-datagrid
            after:git-hub-treeview
            class:col-xs-12 col-md-6 prepend-top git-hub-grid
            widgets
              table
                class:table table-hover
                role:button
                widgets
                  thead
                    widgets
                      tr
                        widgets
                          td
                            innerValue:"Files"
                  tbody
                    widgets

        /*
         * Creates the "file-view" widget that shows the content of our files.
         * Expects URL to file to display as [_arg].
         */
        sys42.samples.git-hub._create-file-view-widget

          /*
           * Deleting any previously created markdown widgets, if existing.
           */
          if
            fetch:x:/0/0?value
              widget-exists:git-hub-markdown
            delete-widget:git-hub-markdown

          /*
           * Massaging URL.
           */
          replace:x:/../*/_arg?value
            src:"https://github.com"
            dest:"https://raw.githubusercontent.com"
          replace:x:/@replace?value
            src:"/blob/master/"
            dest:"/master/"

          /*
           * Retrieving Markdown file, creating HTML out of it, 
           * and creating our result widget showing file.
           */
          p5.http.get:x:/@replace?value
          if:x:/@p5.http.get/*/result/*/Content-Type?value
            !~:text/plain

            // We only handle text types of files.
            sys42.windows.info-tip:File is not a text file.
            return

          // Checking type of file.
          if:x:/@replace?value
            ~:.md

            // Markdown file.
            index-of:x:/@replace?value
              src:/
            split:x:/@replace?value
              =:x:/@index-of/0/-?value
            markdown2html:x:/@p5.http.get/**/content?value
              root-url:{0}/
                :x:/@split/0?name
            create-widget:git-hub-markdown
              parent:results-wrapper
              class:col-xs-12 prepend-top git-hub-markdown
              element:div
              innerValue:x:/@markdown2html?value

          else

            // Source code file.
            p5.html.html-encode:x:/@p5.http.get/**/content?value
            create-widget:git-hub-markdown
              parent:results-wrapper
              class:col-xs-12 prepend-top git-hub-markdown
              element:pre
              oninit
                p5.web.send-javascript:@"hljs.highlightBlock(p5.$('{0}').el);"
                  :x:/../*/_event?value
              innerValue:x:/@p5.html.html-encode?value

      widgets

        /*
         * This is our input for having user supply the URL to some GitHub project website.
         */
        container
          class:input-group
          widgets
            span
              class:input-group-addon
              innerValue:URL
            void:url
              placeholder:GitHub project's URL ...
              class:form-control
              accesskey:U
              value:"https://github.com/"
            container
              class:input-group-btn
              widgets

                /*
                 * Button will download main GitHub project's landing page, 
                 * and semantically parse the HTML for any sub-folders and all of its source files.
                 * Will use this result for creating a "folder Ajax TreeView" to allow you to browse
                 * the project structure, in addition to a "files datagrid" allowing you 
                 * to view the content of each file.
                 */
                button
                  class:btn btn-primary
                  innerValue:Fetch
                  onclick

                    /*
                     * Clearing out any previous results.
                     */
                    clear-widget:results-wrapper

                    /*
                     * Retrieving root URL for project, and fiding all "xxx.md" types of files, 
                     * in addition to all folders.
                     */
                    get-widget-property:url
                      value
                    sys42.samples.git-hub._get-files-folders:x:/@get-widget-property/*/*?value

                    /*
                     * Verifying that we actually found something worth looking at.
                     */
                    if:x:/@sys42.samples.git-hub._get-files-folders/*/*
                      not
                      sys42.windows.info-tip:No folders or files found at specified URL
                        class:info-window info-window-error
                      return

                    /*
                     * Creates our Ajax TreeView for navigating folders.
                     */
                    add:x:/../*/sys42.samples.git-hub._create-tree-view
                      src:x:/@sys42.samples.git-hub._get-files-folders/*(/.folders|/.files)
                    sys42.samples.git-hub._create-tree-view:x:/@get-widget-property/*/*?value

        /*
         * Used to hold our results widgets.
         * Both the TreeView, DataGrid and markdown/code widgets are appended as children into this bugger.
         */
        container:results-wrapper

Then create a “lambda” page in the CMS of System42, with the following code in it, to consume the widget we created above.

/*
 * This will create a page, consuming our newly created 
 * extension widget.
 */
create-widget
  parent:content
  class:col-xs-12
  widgets
    sys42.samples.git-hub.file-browser

Notice, this code example, like most other examples here on my blog, requires both Phosphorus Five, in addition to System42.

PS!
If you want to use the above as a “persisted extension widget”, you’ll need to stuff it in a Hyperlambda file, and make sure your file is evaluated as the server is started.

PPS!
This code is dependent upon the very latest release of both Phosphorus Five and System42 to function, version “Zen 2.1” that is.

KUDOS

KUDOS to highlight.js; I want to give som KUDOS to the guy who created highlight.js, which is a great JavaScript library, allowing anyone to easily show code as syntax highlighted in their web projects. Thank you Ivan Dementev for Open Source licensing your great library. Great work dude! 🙂

In addition, I want to give KUDOS to the Knagis for sharing his brilliant CommonMark.NET library with the world! Great work! For the record, I have a feature request for you, which is to have the option of having a separate URL resolver for images and hyperlinks. Pliiis …? 🙂

Advertisements

Create 156 times faster apps with P5 than with ExtJS

When it comes to Ajax, size is everything. The less bandwidth your apps consume, the more responsive they will be. In the video below, I am demonstrating in a reproducible environment, how creating a simple Ajax TreeView in ExtJS consumes 156 times the amount of bandwidth as creating the same in Phosphorus Five.

This translates into that if you’re on a really shitty internet connection, where it requires 1 second to download the P5 Ajax TreeView – It would require 2.5 minutes to download the ExtJS equivalent.

The reasons for this, is because of a concept in P5 I often refer to as “Managed Ajax”, which allows you to build almost any Ajax control you wish, and rarely if ever exceed ~5KB of JavaScript. So while you’d have to download several megabytes of JavaScript to build a simple Ajax Tree control in ExtJS, you can get away with ~5 kilobytes doing the same with P5.

If you wish to reproduce my performance test, you can find the Hyperlambda necessary to do that below the video.

Create a new “lambda” page in the System42 CMS, paste in the following code, and make sure you set its “template” settings to “empty”.

create-widget
  parent:content
  widgets
    sys42.widgets.tree
      crawl:true
      items
        root:/
      .on-get-items
        list-folders:x:/../*/_item-id?value
        for-each:x:/@list-folders/*?name
          list-folders:x:/@_dp?value
          split:x:/@_dp?value
            =:/
          add:x:/../*/return/*
            src:@"{0}:{1}"
              :x:/@split/0/-?name
              :x:/@_dp?value
          if:x:/@list-folders/*
            not
            add:x:/../*/return/*/items/0/-
              src
                class:tree-leaf
        return
          items

Creating an Ajax TreeView control without JavaScript making you 300 times more productive

In my previous blog, it might sound like as if I am lying through my teeth. However, once you realise how it’s done, there’s actually no magic to it. In p5.ajax, there is one JavaScript file. This is a general purpose JavaScript file, which takes care of serialising the form, updating attributes on DOM elements, and dynamically injecting new HTML snippets from JSON returned from the server.

These above traits though, just so happens to allow me to treat Ajax widgets, in an entirely new way. For instance, the animation you see in the video on my previous blog when I expand the tree nodes, is actually just a CSS animation. The toggling of nodes, occurs exclusively on the server. This allows me to have an entirely new way of dealing with the problem of Ajax, which is simply superior in regards to staying close to the “philosophy of the web”, and semantically much more true to the original design decisions of HTML.

For instance, one thing I didn’t even touch upon in the previous blog, was how the P5 Ajax TreeView can be crawled by search engine spiders, since the spider only see plain old pure hyperlinks – While a client with JavaScript enabled sees DOM events, raising Ajax requests. Semantically, these two different ways of seeing the DOM, ends up with the exact same results. So there’s no “cloaking” occurring. And it 100% perfectly degrades into plain Hyperlinks, if the client has turned off JavaScript for some reasons.

The above combined with the ability to incrementally create my markup and DOM, by composing widgets together, into rich hierarchies from the server – Just so happens to allow me to get away, with creating a fully fledged Ajax TreeView control, without ever having to expand upon my original JavaScript, beyond the 4.8KB that p5.ajax contains at its core.

The results hence becomes that of ending up with an Ajax TreeView, far superior to most other Ajax TreeView in the world, regardless of which parameter you measure it by – WITHOUT as much as a single line of JavaScript! This widget is also entirely created in Hyperlambda, and doesn’t even contain as much as a single line of C# code.

If you’re interested in seeing its code, you can check it out here, here, here, here, here and here. Basically 6 files of Hyperlambda, which are in total 717 lines of code (most of it comments) – Resulting in a reusable general purpose Ajax TreeView control, which are several orders of magnitudes better performance wise, than anything else out there – At least as far as I have seen.

It doesn’t matter who’s Ajax Tree you compare it against either, it’s basically a slaughter, regardless of which Ajax component vendor’s Tree you do the comparison towards; ExtJS/Sencha, Telerik, jQuery, Infragistics, ComponentOne, etc, etc, etc – Basically several orders of magnitude in difference! To give you an idea why, realise that jQuery in its zipped and minified version is at least 25KB. p5.core’s JavaScript is less than 5KB!

And to consume it, is as simple as the following example shows. Realise this is 25 lines of code for the record.

create-widget
  parent:content
  widgets
    sys42.widgets.tree
      crawl:true
      items
        root:/
      .on-get-items
        list-folders:x:/../*/_item-id?value
        for-each:x:/@list-folders/*?name
          list-folders:x:/@_dp?value
          split:x:/@_dp?value
            =:/
          add:x:/../*/return/*
            src:@"{0}:{1}"
              :x:/@split/0/-?name
              :x:/@_dp?value
          if:x:/@list-folders/*
            not
            add:x:/../*/return/*/items/0/-
              src
                class:tree-leaf
        return
          items

To illustrated these reusability features of p5.ajax, lets imagine we wanted to create another Ajax TreeView, a specialised version this time, out of the above code. This specialised version would allow us to inject a “folder browsing Ajax TreeView” into any page we wanted to in our system. Well, that’s as easy as creating an Active Event with the following code.

create-event:my-company.my-folder-tree-view
  return
    sys42.widgets.tree
      crawl:true
      items
        root:/
      .on-get-items
        list-folders:x:/../*/_item-id?value
        for-each:x:/@list-folders/*?name
          list-folders:x:/@_dp?value
          split:x:/@_dp?value
            =:/
          add:x:/../*/return/*
            src:@"{0}:{1}"
              :x:/@split/0/-?name
              :x:/@_dp?value
          if:x:/@list-folders/*
            not
            add:x:/../*/return/*/items/0/-
              src
                class:tree-leaf
        return
          items

After you’ve evaluated the above code in e.g. your Executor, you can create a CMS “lambda” page resembling the following.

create-widget
  parent:content
  class:col-xs-12
  widgets
    my-company.my-folder-tree-view

Notice BTW, that I changed less than 5 lines of code, and was able to create a control out of my existing code. At this point, we can include any “folder browsing Ajax TreeView” we wish, into any page we wish, with a single line of Hyperlambda! Most other Ajax vendors would require you to write hundreds of lines of code, often in 2-3 different programming languages to do the same. So let’s make a qualified guess and say roughly 300 lines of code, reduced to 1 line of code!

According to scientific studies on coding and productivity, which shows that your productivity is proportional to the number of lines you code and have to maintain – You are hence 300 times as productive with Phosphorus Five!

Not too bad for 0KB of JavaScript if you ask me … 😉

Hyperlambda, Zen, and the vanishing Liskov substitution principle

Zen is said to be the mental art of “nothing”. A Zen master once said, when you start out with Zen, the Buddha is everything. When you’re a Zen master, the Buddha disappears. The whys of this, eludes explanation, since it according to the Buddha himself is a realisation.

Phosphorus Five and System42 have similar traits. System42 is “the Buddha”, and Phosphorus Five is the goal. Once you’ve become a Zen master in P5, System42 vanishes.

Therefor, in my upcoming release, I have consciously removed System42 out from the P5 core, and created two separate projects out of these two very much different beasts. The reasons for this, will become obvious for you, as you become a Hyperlambda Zen master!

So what does this have to do with LSP?

LSP is arguably the single largest software architecture problem that has ever existed on the planet. Even extremely seasoned software architects seems to struggle with this problem every now and then. It is based upon the idea that unless one class is a perfect substitution to another class, they cannot inherit from each other in any ways. The textbook example of such a violation of the LSP problem, is having a square inherit from a rectangle.

For the above mentioned reasons, most senior architects will repeat the following mantra; “Prefer composition in favour of inheritance”.

In P5 there are no types. Or to be accurate, there is one type, but every single object in the system, is of the same type. This type is of course the “lambda type”. This means that LSP in regards to types is completely obsolete. In addition, it means that any lambda object, is a perfect substitute to any other lambda objects in your system.

My classic example of a violation of the LSP problem, that illustrates how the LSP problem disappears in Hyperlambda, is the System.Web.UI.Page class from ASP.NET. This class happens to inherit indirectly from System.Web.UI.Control. This is a clear violation of the Liskov substitution principle, since clearly a Page is not a perfect substitute to a Control.

When Microsoft originally created the ASP.NET class hierarchy, they had undoubtedly done their best. They also employed some of the best software architects on the planet in the process – .Net Framework is in general a really, really good piece of work! However, the above LSP problem, tells us something important.

If Microsoft couldn’t get this right, who do you think you are to get it right?

Facts are, LSP is very, very, very difficult – Even for senior architects! So completely eliminating all LSP problems, holds an extreme amount of value, for your ability to architect great solutions.

Hyperlambda does not have this problem. Let me illustrate that fact, by creating a “Hyperlambda user control”, which can take any existing [p5.page] object, and use it as a “control”. This proves that in Hyperlambda and P5, a page truly is substitutable with a control, and vice versa. The code below is fetched from “the guide”, and you can find the whole example code and explanation here.

Below is a piece of code that does two things. It creates an Active Event, which serves as a “User Control”, or custom widget. In addition it inserts a [p5.page] object into your p5.data database.

/*
 * This inserts a new page into our database.
 */
p5.data.insert
  p5.page:/sys42-examples-dox-page
    role:root
    name:A page, that becomes a control
    template:/system42/apps/CMS/page-templates/no-navbar-menu.hl
    type:lambda
    lambda:@"create-widget
  element:button
  innerValue:Click me!
  onclick
    set-widget-property:x:/../*/_event?value
      innerValue:I was clicked!"

/*
 * This creates a "user control" Active Event,
 * which can take a [page] argument, that transforms
 * an existing [p5.page] object, into a "user control".
 */
create-event:sys42.examples.dox.create-control-from-page

  /*
   * Selects the given [page] argument from database, 
   * assuming it is a [p5.page] object type.
   */
  select-data:x:@"/*/*/p5.page/""={0}"""
    :x:/../*/page?value
  if:x:/@select-data/*
    not
    throw:Sorry, couldn't find that page

  /*
   * Adding results from above [select-data]
   * into [return] at the end of event.
   * Making sure we transform its Hyperlambda content
   * to a lambda object first.
   * Notice, we also "sanity check" page, making 
   * sure it has only one root node, that actually creates
   * some widget first!
   */
  hyper2lambda:x:/@select-data/*/*/lambda?value
  if:x:/@hyper2lambda/*?count
    !=:int:1
    or:x:/@hyper2lambda/0?name
      !~:create
    throw:Sorry, I cannot transform that page to a control
  add:x:/../*/return
    src:x:/@hyper2lambda/*

  /*
   * Modifying the [create-widget] invocation to either a
   * [literal], [void] or [container] node, according to what
   * type the root node of our page is.
   */
  if:x:/../*/return/0?name
    ~:-container-
    or:x:/../*/return/0/*/widgets

    /*
     * Page creates a "root container" widget.
     */
    set:x:/../*/return/0?name
      src:container

  else-if:x:/../*/return/0?name
    ~:-literal-
    or:x:/../*/return/0/*/innerValue

    /*
     * Page creates a "root literal" widget.
     */
    set:x:/../*/return/0?name
      src:literal

  else

    /*
     * Page creates a "root void" widget.
     */
    set:x:/../*/return/0?name
      src:void

  return

After you have evaluated the above code, you can consume your newly created custom widget, to load up the page you inserted above, and treat it like a “control”. Do this with something resembling the following. Make sure you create a new “lambda” page in your CMS, and paste in the following code.

create-widget
  parent:content
  widgets
    literal
      element:h1
      innerValue:A page that consumes a page!
    sys42.examples.dox.create-control-from-page
      page:/sys42-examples-dox-page

As you can see with your own eyes, in Hyperlambda a “control” can clearly be substituted with a “page”, and vice versa. Hence, the Liskov substitution principle has vanished. Let me repeat that again once more, to make sure it sticks …

The Liskov substitution problem has vanished!

Facts are, every single problem on the planet can be solved by making things vanish. If you don’t believe me, check out how I solved the unified theory of science, by making the universe disappear

Is it possible hack Phosphorus Five with SQL injection?

The reason why I ask this question, is because a scientific database was recently hacked in the area where I previously used to live. The main IT magazine of Norway, wrote about the hack, because the hacker who hacked it, or rather proved it was possible, tipped of this IT magazine as a “white hat hacker”.

The answer to the above question though, is; “Yes, but you’d have to break every single best practice in P5 to allow for it.” The default and recommended way to create MySQL queries in P5, is by using the SqlParameter collection. This makes it impossible to create an SQL injection attack on anything running P5. An example of a MySQL query can be found below.

p5.mysql.connect:[connection]
  p5.mysql.select:@"select * from customer where name = @name"
    @name:x:/../*/name-argument?value

This will make sure the given “name-argument” is correctly added into the SQL as an SQL Parameter, and not simply concatenated as a string into the resulting SQL. For the record, you should never create your own SQLs simply by concatenating strings. At least not when parts of that string, is created using parameters typed into some web form by an end user. The reason is because the end user might type in something like this; “x’\r\nselect password, username from users” – Which of course will result in the end user having access to all username and/or passwords for your database.

Hyperlambda, a new approach to creating domain specific programming languages

In Hyperlambda, there is no difference between a “function” and a “keyword”. It’s all based upon hierarchical graph objects anyways. One of the really cool consequences of this, is that it is really easy to create what’s commonly referred to as “domain specific programming languages”. These are narrow programming languages, exclusively intended for some specific domain, such as accounting, CRM, etc.

You could for instance create a “keyword” named “create-contact”, and it would become a fully fledged keyword, inseparable from things such as “if”, “while” and “for-each”.

This allows you to create your own programming language, according to your specific needs. Below is an example of how to create an Active Event, that will become a fully fledged keyword, inseparable from any other keywords in the language. First comes the Hyperlambda version of creating such a keyword.

create-event:create-customer
  /*
   * Stuff to create customer goes in here ...
   */

Then to consume this newly created keyword, would imply something like the following.

create-customer
  name:John Doe
  param2:Parameter 2 value

Etc …

This allows you to create your own vocabulary, according to your domain specific needs, facilitating for your own unique programming language. Of course, creating something similar also in C#, is equally simply.

[ActiveEvent (name = "create-customer")]
private void create_customer (ApplicationContext context, ActiveEventArgs e)
{
   /*
    * Do stuff with e.Args here ...
    */
}

This is one of the coolest features of Hyperlambda if you ask me. Hyperlambda is whatever you want it to be, really …