diff --git a/lc-elements-sdk/build.gradle b/lc-elements-sdk/build.gradle
new file mode 100644
index 0000000000000000000000000000000000000000..327a11b7dbf761182a12e511c680febe6218ea25
--- /dev/null
+++ b/lc-elements-sdk/build.gradle
@@ -0,0 +1,23 @@
+plugins {
+    id 'java'
+}
+
+group 'leighco'
+version '1.0'
+
+sourceCompatibility = JavaVersion.VERSION_11
+targetCompatibility = JavaVersion.VERSION_11
+
+repositories {
+    mavenCentral()
+}
+
+dependencies {
+    implementation project(':lc-eo-schema')
+    testImplementation 'org.junit.jupiter:junit-jupiter-api:5.8.1'
+    testRuntimeOnly 'org.junit.jupiter:junit-jupiter-engine:5.8.1'
+}
+
+test {
+    useJUnitPlatform()
+}
\ No newline at end of file
diff --git a/lc-elements-sdk/src/main/java/lc/elements/schema/SchemaGenerator.java b/lc-elements-sdk/src/main/java/lc/elements/schema/SchemaGenerator.java
new file mode 100644
index 0000000000000000000000000000000000000000..ed59f56d61fb524d2f650ad366f1d16dcdfcbd4f
--- /dev/null
+++ b/lc-elements-sdk/src/main/java/lc/elements/schema/SchemaGenerator.java
@@ -0,0 +1,91 @@
+/*
+ * Copyright (c) 2004-2017, by Alex Leigh.
+ * All rights reserved.
+ *
+ * THIS IS UNPUBLISHED PROPRIETARY SOURCE CODE
+ * The copyright notice above does not evidence any
+ * actual or intended publication of such source code.
+ */
+
+package lc.elements.schema;
+
+import lc.eo.EO;
+import lc.eo.EODataType;
+import lc.eo.schema.DAOGenerator;
+import lc.eo.schema.ElementElementDAO;
+import lc.eo.schema.SchemaElementDAO;
+import lc.eo.schema.util.AttributeUtil;
+import lc.mecha.log.MechaLogger;
+import lc.mecha.log.MechaLoggerFactory;
+import lc.mecha.util.UniversalJob;
+
+import java.io.File;
+import java.io.FileWriter;
+import java.io.IOException;
+import java.io.PrintWriter;
+
+/**
+ * Generate the schema for lc-eo-changestream.
+ *
+ * @author Alex Leigh
+ * @since mk1
+ */
+public final class SchemaGenerator {
+    private static final MechaLogger logger = MechaLoggerFactory.getLogger(SchemaGenerator.class);
+    private static final String BASE_PKG = "lc.elements.v1";
+
+    // Observe the procedures of a general alert
+
+    public static EO generate() {
+        final EO schema = lc.eo.schema.util.SchemaUtil.create(BASE_PKG + ".Schema");
+
+        final EO textField = ElementElementDAO.create();
+        SchemaElementDAO.getElements(schema).add(textField);
+        ElementElementDAO.setEoType(textField, BASE_PKG + ".TextField");
+        ElementElementDAO.getAttributes(textField).add(AttributeUtil.create("label", "Label"));
+        ElementElementDAO.getAttributes(textField).add(AttributeUtil.create("isReadOnly", "Read-Only", EODataType.bool));
+
+        final EO formLayout = ElementElementDAO.create();
+        SchemaElementDAO.getElements(schema).add(formLayout);
+        ElementElementDAO.setEoType(formLayout, BASE_PKG + ".FormLayout");
+        ElementElementDAO.getAttributes(formLayout).add(AttributeUtil.create("content", "Content", EODataType.loop));
+
+        final EO tableColCfg = ElementElementDAO.create();
+        SchemaElementDAO.getElements(schema).add(tableColCfg);
+        ElementElementDAO.setEoType(tableColCfg, BASE_PKG + ".TableColumnCfg");
+        ElementElementDAO.getAttributes(tableColCfg).add(AttributeUtil.create("label", "Label"));
+        ElementElementDAO.getAttributes(tableColCfg).add(AttributeUtil.create("width", "Width (chars)"));
+        ElementElementDAO.getAttributes(tableColCfg).add(AttributeUtil.create("alignment", "Alignment"));
+        ElementElementDAO.getAttributes(tableColCfg).add(AttributeUtil.create("isReadOnly", "Read-Only", EODataType.bool));
+
+        final EO panel = ElementElementDAO.create();
+        SchemaElementDAO.getElements(schema).add(panel);
+        ElementElementDAO.setEoType(panel, BASE_PKG + ".Panel");
+        ElementElementDAO.getAttributes(panel).add(AttributeUtil.create("label", "Label"));
+        ElementElementDAO.getAttributes(panel).add(AttributeUtil.create("content", "Content", EODataType.loop));
+
+        final EO table = ElementElementDAO.create();
+        SchemaElementDAO.getElements(schema).add(table);
+        ElementElementDAO.setEoType(table, BASE_PKG + ".Table");
+        ElementElementDAO.getAttributes(table).add(AttributeUtil.create("isReadOnly", "Read-Only", EODataType.bool));
+        ElementElementDAO.getAttributes(table).add(AttributeUtil.create("columns", "Columns", EODataType.loop));
+
+        final EO screen = ElementElementDAO.create();
+        SchemaElementDAO.getElements(schema).add(screen);
+        ElementElementDAO.setEoType(screen, BASE_PKG + ".Screen");
+        ElementElementDAO.getAttributes(screen).add(AttributeUtil.create("content", "Content", EODataType.loop));
+
+        return schema;
+    }
+
+    public static void main(final String... args) throws IOException {
+        UniversalJob.banner(logger, "Apotheosis mk3", "2014-2022 Alex Leigh");
+        final EO schema = generate();
+        final DAOGenerator gen = new DAOGenerator(new File("lc-elements-sdk/src/main/java"));
+        gen.generateJava("lc.elements.schema.v1", schema);
+        try (PrintWriter pw = new PrintWriter(new FileWriter(new File("out.js")))) {
+            gen.generateEcma5(pw, "lc.elements.schema.v1", schema);
+        }
+        logger.info("Generated schema: {}", schema);
+    }
+}
diff --git a/lc-elements-sdk/src/main/java/lc/elements/schema/v1/FormLayoutElementDAO.java b/lc-elements-sdk/src/main/java/lc/elements/schema/v1/FormLayoutElementDAO.java
new file mode 100644
index 0000000000000000000000000000000000000000..28962c7d8a7e16b76527e1b1d9a80e372c6166da
--- /dev/null
+++ b/lc-elements-sdk/src/main/java/lc/elements/schema/v1/FormLayoutElementDAO.java
@@ -0,0 +1,73 @@
+/*
+ * Copyright (c) 2014-2022, by Alex Leigh.
+ * All rights reserved.
+ *
+ * THIS IS UNPUBLISHED PROPRIETARY SOURCE CODE
+ * The copyright notice above does not evidence any
+ * actual or intended publication of such source code.
+ */
+
+package lc.elements.schema.v1;
+
+import lc.eo.EO;
+
+/**
+ * This is a dynamically generated DAO class for accessing objects within an ESP graph. This class
+ * has been generated by <code>DAOGenerator</code> and should not be modified.
+ *
+ * @author DAOGenerator (synthetically generated class)
+ */
+public final class FormLayoutElementDAO {
+    public static final String API_TYPE = "lc.elements.v1.FormLayout";
+
+    public static EO create() {
+        EO eo = new EO(API_TYPE);
+        return eo;
+    }
+
+    public static boolean assertType(final EO eo) {
+        return eo.getType().equals(API_TYPE);
+    }
+
+    public static final String KEY_CONTENT = "content";
+
+    public static String apiType(final EO eo) {
+        return eo.getType();
+    }
+
+
+    /* EO{typeName='lc.eo.schema.Attribute', data={eoType=content, label=EOLoop{array=[EO{typeName='lc.eo.schema.Text', data={text=Content, locale=en}, meta=null}]} , type=loop}, meta=null} */
+
+
+    public static lc.eo.EOLoop getContent(EO eo) {
+        if (!assertType(eo))
+            throw new IllegalArgumentException("Mismatched EO type: [found: " + eo.getType() + "] [expected: " + API_TYPE + "]");
+        return eo.getValueLoop(KEY_CONTENT);
+    }
+
+    public static void setContent(final EO eo, lc.eo.EOLoop value) {
+        if (!assertType(eo))
+            throw new IllegalArgumentException("Mismatched EO type: [found: " + eo.getType() + "] [expected: " + API_TYPE + "]");
+        eo.setValue(KEY_CONTENT, value);
+    }
+
+    public static void setContentLabel(final EO eo, final String label) {
+        if (!assertType(eo))
+            throw new IllegalArgumentException("Mismatched EO type: [found: " + eo.getType() + "] [expected: " + API_TYPE + "]");
+        eo.setLabel(KEY_CONTENT, label);
+    }
+
+    public static void getLabelOrValueContent(final EO eo, lc.eo.EOLoop value) {
+        if (!assertType(eo))
+            throw new IllegalArgumentException("Mismatched EO type: [found: " + eo.getType() + "] [expected: " + API_TYPE + "]");
+        eo.getLabelOrValue(KEY_CONTENT);
+    }
+
+    public static void setIfUnsetContent(final EO eo, lc.eo.EOLoop value) {
+        if (!assertType(eo))
+            throw new IllegalArgumentException("Mismatched EO type: [found: " + eo.getType() + "] [expected: " + API_TYPE + "]");
+        eo.setValueIfUnset(KEY_CONTENT, value);
+    }
+
+
+}
\ No newline at end of file
diff --git a/lc-elements-sdk/src/main/java/lc/elements/schema/v1/PanelElementDAO.java b/lc-elements-sdk/src/main/java/lc/elements/schema/v1/PanelElementDAO.java
new file mode 100644
index 0000000000000000000000000000000000000000..233b15dd12c7e19113cf51ebc08d62c917c4927e
--- /dev/null
+++ b/lc-elements-sdk/src/main/java/lc/elements/schema/v1/PanelElementDAO.java
@@ -0,0 +1,108 @@
+/*
+ * Copyright (c) 2014-2022, by Alex Leigh.
+ * All rights reserved.
+ *
+ * THIS IS UNPUBLISHED PROPRIETARY SOURCE CODE
+ * The copyright notice above does not evidence any
+ * actual or intended publication of such source code.
+ */
+
+package lc.elements.schema.v1;
+
+import lc.eo.EO;
+
+/**
+ * This is a dynamically generated DAO class for accessing objects within an ESP graph. This class
+ * has been generated by <code>DAOGenerator</code> and should not be modified.
+ *
+ * @author DAOGenerator (synthetically generated class)
+ */
+public final class PanelElementDAO {
+    public static final String API_TYPE = "lc.elements.v1.Panel";
+
+    public static EO create() {
+        EO eo = new EO(API_TYPE);
+        return eo;
+    }
+
+    public static boolean assertType(final EO eo) {
+        return eo.getType().equals(API_TYPE);
+    }
+
+    public static final String KEY_LABEL = "label";
+    public static final String KEY_CONTENT = "content";
+
+    public static String apiType(final EO eo) {
+        return eo.getType();
+    }
+
+
+    /* EO{typeName='lc.eo.schema.Attribute', data={eoType=label, label=EOLoop{array=[EO{typeName='lc.eo.schema.Text', data={text=Label, locale=en}, meta=null}]} , type=string}, meta=null} */
+
+
+    public static java.lang.String getLabel(EO eo) {
+        if (!assertType(eo))
+            throw new IllegalArgumentException("Mismatched EO type: [found: " + eo.getType() + "] [expected: " + API_TYPE + "]");
+        return eo.getValueString(KEY_LABEL);
+    }
+
+    public static void setLabel(final EO eo, java.lang.String value) {
+        if (!assertType(eo))
+            throw new IllegalArgumentException("Mismatched EO type: [found: " + eo.getType() + "] [expected: " + API_TYPE + "]");
+        eo.setValue(KEY_LABEL, value);
+    }
+
+    public static void setLabelLabel(final EO eo, final String label) {
+        if (!assertType(eo))
+            throw new IllegalArgumentException("Mismatched EO type: [found: " + eo.getType() + "] [expected: " + API_TYPE + "]");
+        eo.setLabel(KEY_LABEL, label);
+    }
+
+    public static void getLabelOrValueLabel(final EO eo, java.lang.String value) {
+        if (!assertType(eo))
+            throw new IllegalArgumentException("Mismatched EO type: [found: " + eo.getType() + "] [expected: " + API_TYPE + "]");
+        eo.getLabelOrValue(KEY_LABEL);
+    }
+
+    public static void setIfUnsetLabel(final EO eo, java.lang.String value) {
+        if (!assertType(eo))
+            throw new IllegalArgumentException("Mismatched EO type: [found: " + eo.getType() + "] [expected: " + API_TYPE + "]");
+        eo.setValueIfUnset(KEY_LABEL, value);
+    }
+
+
+    /* EO{typeName='lc.eo.schema.Attribute', data={eoType=content, label=EOLoop{array=[EO{typeName='lc.eo.schema.Text', data={text=Content, locale=en}, meta=null}]} , type=loop}, meta=null} */
+
+
+    public static lc.eo.EOLoop getContent(EO eo) {
+        if (!assertType(eo))
+            throw new IllegalArgumentException("Mismatched EO type: [found: " + eo.getType() + "] [expected: " + API_TYPE + "]");
+        return eo.getValueLoop(KEY_CONTENT);
+    }
+
+    public static void setContent(final EO eo, lc.eo.EOLoop value) {
+        if (!assertType(eo))
+            throw new IllegalArgumentException("Mismatched EO type: [found: " + eo.getType() + "] [expected: " + API_TYPE + "]");
+        eo.setValue(KEY_CONTENT, value);
+    }
+
+    public static void setContentLabel(final EO eo, final String label) {
+        if (!assertType(eo))
+            throw new IllegalArgumentException("Mismatched EO type: [found: " + eo.getType() + "] [expected: " + API_TYPE + "]");
+        eo.setLabel(KEY_CONTENT, label);
+    }
+
+    public static void getLabelOrValueContent(final EO eo, lc.eo.EOLoop value) {
+        if (!assertType(eo))
+            throw new IllegalArgumentException("Mismatched EO type: [found: " + eo.getType() + "] [expected: " + API_TYPE + "]");
+        eo.getLabelOrValue(KEY_CONTENT);
+    }
+
+    public static void setIfUnsetContent(final EO eo, lc.eo.EOLoop value) {
+        if (!assertType(eo))
+            throw new IllegalArgumentException("Mismatched EO type: [found: " + eo.getType() + "] [expected: " + API_TYPE + "]");
+        eo.setValueIfUnset(KEY_CONTENT, value);
+    }
+
+
+}
\ No newline at end of file
diff --git a/lc-elements-sdk/src/main/java/lc/elements/schema/v1/ScreenElementDAO.java b/lc-elements-sdk/src/main/java/lc/elements/schema/v1/ScreenElementDAO.java
new file mode 100644
index 0000000000000000000000000000000000000000..7064316afede11ca3dd979491c8baf023ede1160
--- /dev/null
+++ b/lc-elements-sdk/src/main/java/lc/elements/schema/v1/ScreenElementDAO.java
@@ -0,0 +1,73 @@
+/*
+ * Copyright (c) 2014-2022, by Alex Leigh.
+ * All rights reserved.
+ *
+ * THIS IS UNPUBLISHED PROPRIETARY SOURCE CODE
+ * The copyright notice above does not evidence any
+ * actual or intended publication of such source code.
+ */
+
+package lc.elements.schema.v1;
+
+import lc.eo.EO;
+
+/**
+ * This is a dynamically generated DAO class for accessing objects within an ESP graph. This class
+ * has been generated by <code>DAOGenerator</code> and should not be modified.
+ *
+ * @author DAOGenerator (synthetically generated class)
+ */
+public final class ScreenElementDAO {
+    public static final String API_TYPE = "lc.elements.v1.Screen";
+
+    public static EO create() {
+        EO eo = new EO(API_TYPE);
+        return eo;
+    }
+
+    public static boolean assertType(final EO eo) {
+        return eo.getType().equals(API_TYPE);
+    }
+
+    public static final String KEY_CONTENT = "content";
+
+    public static String apiType(final EO eo) {
+        return eo.getType();
+    }
+
+
+    /* EO{typeName='lc.eo.schema.Attribute', data={eoType=content, label=EOLoop{array=[EO{typeName='lc.eo.schema.Text', data={text=Content, locale=en}, meta=null}]} , type=loop}, meta=null} */
+
+
+    public static lc.eo.EOLoop getContent(EO eo) {
+        if (!assertType(eo))
+            throw new IllegalArgumentException("Mismatched EO type: [found: " + eo.getType() + "] [expected: " + API_TYPE + "]");
+        return eo.getValueLoop(KEY_CONTENT);
+    }
+
+    public static void setContent(final EO eo, lc.eo.EOLoop value) {
+        if (!assertType(eo))
+            throw new IllegalArgumentException("Mismatched EO type: [found: " + eo.getType() + "] [expected: " + API_TYPE + "]");
+        eo.setValue(KEY_CONTENT, value);
+    }
+
+    public static void setContentLabel(final EO eo, final String label) {
+        if (!assertType(eo))
+            throw new IllegalArgumentException("Mismatched EO type: [found: " + eo.getType() + "] [expected: " + API_TYPE + "]");
+        eo.setLabel(KEY_CONTENT, label);
+    }
+
+    public static void getLabelOrValueContent(final EO eo, lc.eo.EOLoop value) {
+        if (!assertType(eo))
+            throw new IllegalArgumentException("Mismatched EO type: [found: " + eo.getType() + "] [expected: " + API_TYPE + "]");
+        eo.getLabelOrValue(KEY_CONTENT);
+    }
+
+    public static void setIfUnsetContent(final EO eo, lc.eo.EOLoop value) {
+        if (!assertType(eo))
+            throw new IllegalArgumentException("Mismatched EO type: [found: " + eo.getType() + "] [expected: " + API_TYPE + "]");
+        eo.setValueIfUnset(KEY_CONTENT, value);
+    }
+
+
+}
\ No newline at end of file
diff --git a/lc-elements-sdk/src/main/java/lc/elements/schema/v1/TableColumnCfgElementDAO.java b/lc-elements-sdk/src/main/java/lc/elements/schema/v1/TableColumnCfgElementDAO.java
new file mode 100644
index 0000000000000000000000000000000000000000..988a54c073fbbb7df877f20896c55d8ae7013d59
--- /dev/null
+++ b/lc-elements-sdk/src/main/java/lc/elements/schema/v1/TableColumnCfgElementDAO.java
@@ -0,0 +1,178 @@
+/*
+ * Copyright (c) 2014-2022, by Alex Leigh.
+ * All rights reserved.
+ *
+ * THIS IS UNPUBLISHED PROPRIETARY SOURCE CODE
+ * The copyright notice above does not evidence any
+ * actual or intended publication of such source code.
+ */
+
+package lc.elements.schema.v1;
+
+import lc.eo.EO;
+
+/**
+ * This is a dynamically generated DAO class for accessing objects within an ESP graph. This class
+ * has been generated by <code>DAOGenerator</code> and should not be modified.
+ *
+ * @author DAOGenerator (synthetically generated class)
+ */
+public final class TableColumnCfgElementDAO {
+    public static final String API_TYPE = "lc.elements.v1.TableColumnCfg";
+
+    public static EO create() {
+        EO eo = new EO(API_TYPE);
+        return eo;
+    }
+
+    public static boolean assertType(final EO eo) {
+        return eo.getType().equals(API_TYPE);
+    }
+
+    public static final String KEY_LABEL = "label";
+    public static final String KEY_WIDTH = "width";
+    public static final String KEY_ALIGNMENT = "alignment";
+    public static final String KEY_ISREADONLY = "isReadOnly";
+
+    public static String apiType(final EO eo) {
+        return eo.getType();
+    }
+
+
+    /* EO{typeName='lc.eo.schema.Attribute', data={eoType=label, label=EOLoop{array=[EO{typeName='lc.eo.schema.Text', data={text=Label, locale=en}, meta=null}]} , type=string}, meta=null} */
+
+
+    public static java.lang.String getLabel(EO eo) {
+        if (!assertType(eo))
+            throw new IllegalArgumentException("Mismatched EO type: [found: " + eo.getType() + "] [expected: " + API_TYPE + "]");
+        return eo.getValueString(KEY_LABEL);
+    }
+
+    public static void setLabel(final EO eo, java.lang.String value) {
+        if (!assertType(eo))
+            throw new IllegalArgumentException("Mismatched EO type: [found: " + eo.getType() + "] [expected: " + API_TYPE + "]");
+        eo.setValue(KEY_LABEL, value);
+    }
+
+    public static void setLabelLabel(final EO eo, final String label) {
+        if (!assertType(eo))
+            throw new IllegalArgumentException("Mismatched EO type: [found: " + eo.getType() + "] [expected: " + API_TYPE + "]");
+        eo.setLabel(KEY_LABEL, label);
+    }
+
+    public static void getLabelOrValueLabel(final EO eo, java.lang.String value) {
+        if (!assertType(eo))
+            throw new IllegalArgumentException("Mismatched EO type: [found: " + eo.getType() + "] [expected: " + API_TYPE + "]");
+        eo.getLabelOrValue(KEY_LABEL);
+    }
+
+    public static void setIfUnsetLabel(final EO eo, java.lang.String value) {
+        if (!assertType(eo))
+            throw new IllegalArgumentException("Mismatched EO type: [found: " + eo.getType() + "] [expected: " + API_TYPE + "]");
+        eo.setValueIfUnset(KEY_LABEL, value);
+    }
+
+
+    /* EO{typeName='lc.eo.schema.Attribute', data={eoType=width, label=EOLoop{array=[EO{typeName='lc.eo.schema.Text', data={text=Width (chars), locale=en}, meta=null}]} , type=string}, meta=null} */
+
+
+    public static java.lang.String getWidth(EO eo) {
+        if (!assertType(eo))
+            throw new IllegalArgumentException("Mismatched EO type: [found: " + eo.getType() + "] [expected: " + API_TYPE + "]");
+        return eo.getValueString(KEY_WIDTH);
+    }
+
+    public static void setWidth(final EO eo, java.lang.String value) {
+        if (!assertType(eo))
+            throw new IllegalArgumentException("Mismatched EO type: [found: " + eo.getType() + "] [expected: " + API_TYPE + "]");
+        eo.setValue(KEY_WIDTH, value);
+    }
+
+    public static void setWidthLabel(final EO eo, final String label) {
+        if (!assertType(eo))
+            throw new IllegalArgumentException("Mismatched EO type: [found: " + eo.getType() + "] [expected: " + API_TYPE + "]");
+        eo.setLabel(KEY_WIDTH, label);
+    }
+
+    public static void getLabelOrValueWidth(final EO eo, java.lang.String value) {
+        if (!assertType(eo))
+            throw new IllegalArgumentException("Mismatched EO type: [found: " + eo.getType() + "] [expected: " + API_TYPE + "]");
+        eo.getLabelOrValue(KEY_WIDTH);
+    }
+
+    public static void setIfUnsetWidth(final EO eo, java.lang.String value) {
+        if (!assertType(eo))
+            throw new IllegalArgumentException("Mismatched EO type: [found: " + eo.getType() + "] [expected: " + API_TYPE + "]");
+        eo.setValueIfUnset(KEY_WIDTH, value);
+    }
+
+
+    /* EO{typeName='lc.eo.schema.Attribute', data={eoType=alignment, label=EOLoop{array=[EO{typeName='lc.eo.schema.Text', data={text=Alignment, locale=en}, meta=null}]} , type=string}, meta=null} */
+
+
+    public static java.lang.String getAlignment(EO eo) {
+        if (!assertType(eo))
+            throw new IllegalArgumentException("Mismatched EO type: [found: " + eo.getType() + "] [expected: " + API_TYPE + "]");
+        return eo.getValueString(KEY_ALIGNMENT);
+    }
+
+    public static void setAlignment(final EO eo, java.lang.String value) {
+        if (!assertType(eo))
+            throw new IllegalArgumentException("Mismatched EO type: [found: " + eo.getType() + "] [expected: " + API_TYPE + "]");
+        eo.setValue(KEY_ALIGNMENT, value);
+    }
+
+    public static void setAlignmentLabel(final EO eo, final String label) {
+        if (!assertType(eo))
+            throw new IllegalArgumentException("Mismatched EO type: [found: " + eo.getType() + "] [expected: " + API_TYPE + "]");
+        eo.setLabel(KEY_ALIGNMENT, label);
+    }
+
+    public static void getLabelOrValueAlignment(final EO eo, java.lang.String value) {
+        if (!assertType(eo))
+            throw new IllegalArgumentException("Mismatched EO type: [found: " + eo.getType() + "] [expected: " + API_TYPE + "]");
+        eo.getLabelOrValue(KEY_ALIGNMENT);
+    }
+
+    public static void setIfUnsetAlignment(final EO eo, java.lang.String value) {
+        if (!assertType(eo))
+            throw new IllegalArgumentException("Mismatched EO type: [found: " + eo.getType() + "] [expected: " + API_TYPE + "]");
+        eo.setValueIfUnset(KEY_ALIGNMENT, value);
+    }
+
+
+    /* EO{typeName='lc.eo.schema.Attribute', data={eoType=isReadOnly, label=EOLoop{array=[EO{typeName='lc.eo.schema.Text', data={text=Read-Only, locale=en}, meta=null}]} , type=bool}, meta=null} */
+
+
+    public static java.lang.Boolean getIsReadOnly(EO eo) {
+        if (!assertType(eo))
+            throw new IllegalArgumentException("Mismatched EO type: [found: " + eo.getType() + "] [expected: " + API_TYPE + "]");
+        return eo.getValueBoolean(KEY_ISREADONLY);
+    }
+
+    public static void setIsReadOnly(final EO eo, java.lang.Boolean value) {
+        if (!assertType(eo))
+            throw new IllegalArgumentException("Mismatched EO type: [found: " + eo.getType() + "] [expected: " + API_TYPE + "]");
+        eo.setValue(KEY_ISREADONLY, value);
+    }
+
+    public static void setIsReadOnlyLabel(final EO eo, final String label) {
+        if (!assertType(eo))
+            throw new IllegalArgumentException("Mismatched EO type: [found: " + eo.getType() + "] [expected: " + API_TYPE + "]");
+        eo.setLabel(KEY_ISREADONLY, label);
+    }
+
+    public static void getLabelOrValueIsReadOnly(final EO eo, java.lang.Boolean value) {
+        if (!assertType(eo))
+            throw new IllegalArgumentException("Mismatched EO type: [found: " + eo.getType() + "] [expected: " + API_TYPE + "]");
+        eo.getLabelOrValue(KEY_ISREADONLY);
+    }
+
+    public static void setIfUnsetIsReadOnly(final EO eo, java.lang.Boolean value) {
+        if (!assertType(eo))
+            throw new IllegalArgumentException("Mismatched EO type: [found: " + eo.getType() + "] [expected: " + API_TYPE + "]");
+        eo.setValueIfUnset(KEY_ISREADONLY, value);
+    }
+
+
+}
\ No newline at end of file
diff --git a/lc-elements-sdk/src/main/java/lc/elements/schema/v1/TableElementDAO.java b/lc-elements-sdk/src/main/java/lc/elements/schema/v1/TableElementDAO.java
new file mode 100644
index 0000000000000000000000000000000000000000..fb1fe72a543ddd548ca452ee1417283703a43ad2
--- /dev/null
+++ b/lc-elements-sdk/src/main/java/lc/elements/schema/v1/TableElementDAO.java
@@ -0,0 +1,108 @@
+/*
+ * Copyright (c) 2014-2022, by Alex Leigh.
+ * All rights reserved.
+ *
+ * THIS IS UNPUBLISHED PROPRIETARY SOURCE CODE
+ * The copyright notice above does not evidence any
+ * actual or intended publication of such source code.
+ */
+
+package lc.elements.schema.v1;
+
+import lc.eo.EO;
+
+/**
+ * This is a dynamically generated DAO class for accessing objects within an ESP graph. This class
+ * has been generated by <code>DAOGenerator</code> and should not be modified.
+ *
+ * @author DAOGenerator (synthetically generated class)
+ */
+public final class TableElementDAO {
+    public static final String API_TYPE = "lc.elements.v1.Table";
+
+    public static EO create() {
+        EO eo = new EO(API_TYPE);
+        return eo;
+    }
+
+    public static boolean assertType(final EO eo) {
+        return eo.getType().equals(API_TYPE);
+    }
+
+    public static final String KEY_ISREADONLY = "isReadOnly";
+    public static final String KEY_COLUMNS = "columns";
+
+    public static String apiType(final EO eo) {
+        return eo.getType();
+    }
+
+
+    /* EO{typeName='lc.eo.schema.Attribute', data={eoType=isReadOnly, label=EOLoop{array=[EO{typeName='lc.eo.schema.Text', data={text=Read-Only, locale=en}, meta=null}]} , type=bool}, meta=null} */
+
+
+    public static java.lang.Boolean getIsReadOnly(EO eo) {
+        if (!assertType(eo))
+            throw new IllegalArgumentException("Mismatched EO type: [found: " + eo.getType() + "] [expected: " + API_TYPE + "]");
+        return eo.getValueBoolean(KEY_ISREADONLY);
+    }
+
+    public static void setIsReadOnly(final EO eo, java.lang.Boolean value) {
+        if (!assertType(eo))
+            throw new IllegalArgumentException("Mismatched EO type: [found: " + eo.getType() + "] [expected: " + API_TYPE + "]");
+        eo.setValue(KEY_ISREADONLY, value);
+    }
+
+    public static void setIsReadOnlyLabel(final EO eo, final String label) {
+        if (!assertType(eo))
+            throw new IllegalArgumentException("Mismatched EO type: [found: " + eo.getType() + "] [expected: " + API_TYPE + "]");
+        eo.setLabel(KEY_ISREADONLY, label);
+    }
+
+    public static void getLabelOrValueIsReadOnly(final EO eo, java.lang.Boolean value) {
+        if (!assertType(eo))
+            throw new IllegalArgumentException("Mismatched EO type: [found: " + eo.getType() + "] [expected: " + API_TYPE + "]");
+        eo.getLabelOrValue(KEY_ISREADONLY);
+    }
+
+    public static void setIfUnsetIsReadOnly(final EO eo, java.lang.Boolean value) {
+        if (!assertType(eo))
+            throw new IllegalArgumentException("Mismatched EO type: [found: " + eo.getType() + "] [expected: " + API_TYPE + "]");
+        eo.setValueIfUnset(KEY_ISREADONLY, value);
+    }
+
+
+    /* EO{typeName='lc.eo.schema.Attribute', data={eoType=columns, label=EOLoop{array=[EO{typeName='lc.eo.schema.Text', data={text=Columns, locale=en}, meta=null}]} , type=loop}, meta=null} */
+
+
+    public static lc.eo.EOLoop getColumns(EO eo) {
+        if (!assertType(eo))
+            throw new IllegalArgumentException("Mismatched EO type: [found: " + eo.getType() + "] [expected: " + API_TYPE + "]");
+        return eo.getValueLoop(KEY_COLUMNS);
+    }
+
+    public static void setColumns(final EO eo, lc.eo.EOLoop value) {
+        if (!assertType(eo))
+            throw new IllegalArgumentException("Mismatched EO type: [found: " + eo.getType() + "] [expected: " + API_TYPE + "]");
+        eo.setValue(KEY_COLUMNS, value);
+    }
+
+    public static void setColumnsLabel(final EO eo, final String label) {
+        if (!assertType(eo))
+            throw new IllegalArgumentException("Mismatched EO type: [found: " + eo.getType() + "] [expected: " + API_TYPE + "]");
+        eo.setLabel(KEY_COLUMNS, label);
+    }
+
+    public static void getLabelOrValueColumns(final EO eo, lc.eo.EOLoop value) {
+        if (!assertType(eo))
+            throw new IllegalArgumentException("Mismatched EO type: [found: " + eo.getType() + "] [expected: " + API_TYPE + "]");
+        eo.getLabelOrValue(KEY_COLUMNS);
+    }
+
+    public static void setIfUnsetColumns(final EO eo, lc.eo.EOLoop value) {
+        if (!assertType(eo))
+            throw new IllegalArgumentException("Mismatched EO type: [found: " + eo.getType() + "] [expected: " + API_TYPE + "]");
+        eo.setValueIfUnset(KEY_COLUMNS, value);
+    }
+
+
+}
\ No newline at end of file
diff --git a/lc-elements-sdk/src/main/java/lc/elements/schema/v1/TextFieldElementDAO.java b/lc-elements-sdk/src/main/java/lc/elements/schema/v1/TextFieldElementDAO.java
new file mode 100644
index 0000000000000000000000000000000000000000..c65475bfd82de6cc48bfe5dfb1162794316978ea
--- /dev/null
+++ b/lc-elements-sdk/src/main/java/lc/elements/schema/v1/TextFieldElementDAO.java
@@ -0,0 +1,108 @@
+/*
+ * Copyright (c) 2014-2022, by Alex Leigh.
+ * All rights reserved.
+ *
+ * THIS IS UNPUBLISHED PROPRIETARY SOURCE CODE
+ * The copyright notice above does not evidence any
+ * actual or intended publication of such source code.
+ */
+
+package lc.elements.schema.v1;
+
+import lc.eo.EO;
+
+/**
+ * This is a dynamically generated DAO class for accessing objects within an ESP graph. This class
+ * has been generated by <code>DAOGenerator</code> and should not be modified.
+ *
+ * @author DAOGenerator (synthetically generated class)
+ */
+public final class TextFieldElementDAO {
+    public static final String API_TYPE = "lc.elements.v1.TextField";
+
+    public static EO create() {
+        EO eo = new EO(API_TYPE);
+        return eo;
+    }
+
+    public static boolean assertType(final EO eo) {
+        return eo.getType().equals(API_TYPE);
+    }
+
+    public static final String KEY_LABEL = "label";
+    public static final String KEY_ISREADONLY = "isReadOnly";
+
+    public static String apiType(final EO eo) {
+        return eo.getType();
+    }
+
+
+    /* EO{typeName='lc.eo.schema.Attribute', data={eoType=label, label=EOLoop{array=[EO{typeName='lc.eo.schema.Text', data={text=Label, locale=en}, meta=null}]} , type=string}, meta=null} */
+
+
+    public static java.lang.String getLabel(EO eo) {
+        if (!assertType(eo))
+            throw new IllegalArgumentException("Mismatched EO type: [found: " + eo.getType() + "] [expected: " + API_TYPE + "]");
+        return eo.getValueString(KEY_LABEL);
+    }
+
+    public static void setLabel(final EO eo, java.lang.String value) {
+        if (!assertType(eo))
+            throw new IllegalArgumentException("Mismatched EO type: [found: " + eo.getType() + "] [expected: " + API_TYPE + "]");
+        eo.setValue(KEY_LABEL, value);
+    }
+
+    public static void setLabelLabel(final EO eo, final String label) {
+        if (!assertType(eo))
+            throw new IllegalArgumentException("Mismatched EO type: [found: " + eo.getType() + "] [expected: " + API_TYPE + "]");
+        eo.setLabel(KEY_LABEL, label);
+    }
+
+    public static void getLabelOrValueLabel(final EO eo, java.lang.String value) {
+        if (!assertType(eo))
+            throw new IllegalArgumentException("Mismatched EO type: [found: " + eo.getType() + "] [expected: " + API_TYPE + "]");
+        eo.getLabelOrValue(KEY_LABEL);
+    }
+
+    public static void setIfUnsetLabel(final EO eo, java.lang.String value) {
+        if (!assertType(eo))
+            throw new IllegalArgumentException("Mismatched EO type: [found: " + eo.getType() + "] [expected: " + API_TYPE + "]");
+        eo.setValueIfUnset(KEY_LABEL, value);
+    }
+
+
+    /* EO{typeName='lc.eo.schema.Attribute', data={eoType=isReadOnly, label=EOLoop{array=[EO{typeName='lc.eo.schema.Text', data={text=Read-Only, locale=en}, meta=null}]} , type=bool}, meta=null} */
+
+
+    public static java.lang.Boolean getIsReadOnly(EO eo) {
+        if (!assertType(eo))
+            throw new IllegalArgumentException("Mismatched EO type: [found: " + eo.getType() + "] [expected: " + API_TYPE + "]");
+        return eo.getValueBoolean(KEY_ISREADONLY);
+    }
+
+    public static void setIsReadOnly(final EO eo, java.lang.Boolean value) {
+        if (!assertType(eo))
+            throw new IllegalArgumentException("Mismatched EO type: [found: " + eo.getType() + "] [expected: " + API_TYPE + "]");
+        eo.setValue(KEY_ISREADONLY, value);
+    }
+
+    public static void setIsReadOnlyLabel(final EO eo, final String label) {
+        if (!assertType(eo))
+            throw new IllegalArgumentException("Mismatched EO type: [found: " + eo.getType() + "] [expected: " + API_TYPE + "]");
+        eo.setLabel(KEY_ISREADONLY, label);
+    }
+
+    public static void getLabelOrValueIsReadOnly(final EO eo, java.lang.Boolean value) {
+        if (!assertType(eo))
+            throw new IllegalArgumentException("Mismatched EO type: [found: " + eo.getType() + "] [expected: " + API_TYPE + "]");
+        eo.getLabelOrValue(KEY_ISREADONLY);
+    }
+
+    public static void setIfUnsetIsReadOnly(final EO eo, java.lang.Boolean value) {
+        if (!assertType(eo))
+            throw new IllegalArgumentException("Mismatched EO type: [found: " + eo.getType() + "] [expected: " + API_TYPE + "]");
+        eo.setValueIfUnset(KEY_ISREADONLY, value);
+    }
+
+
+}
\ No newline at end of file
diff --git a/qody b/qody
index 42d04a9302ebbd82dae6894067c4ac4db6fee400..e1f32420d9fc0af84db14fe9ee05e50fafc347ce 160000
--- a/qody
+++ b/qody
@@ -1 +1 @@
-Subproject commit 42d04a9302ebbd82dae6894067c4ac4db6fee400
+Subproject commit e1f32420d9fc0af84db14fe9ee05e50fafc347ce
diff --git a/settings.gradle b/settings.gradle
index 71c27d41ad1032beeacdc9c7f3baab05b51531c6..f8994618bffe9de210cd21ca3caeef23c45e6b51 100644
--- a/settings.gradle
+++ b/settings.gradle
@@ -72,4 +72,5 @@ include 'lc-data-flight'
 include 'qody:qody-vision-schema'
 findProject(':qody:qody-vision-schema')?.name = 'qody-vision-schema'
 include 'lc-eo-changestream'
+include 'lc-elements-sdk'