diff --git a/README.md b/README.md
index 4bd8d8e549deb24effee7c342ca28ea43fd3b790..aba8a961dcfcd4801be5d82309e5dc45448f2391 100644
--- a/README.md
+++ b/README.md
@@ -11,6 +11,34 @@ To check out docs and examples, visit [gitlab.schukai.com/oss/bob](https://gitla
 
 ## Usage
 
+### Template
+
+#### Prepare
+
+```bash
+bob template prepare --input ./templates/ --output ./output/
+```
+
+This will create a `./output/` directory with all parsed templates from `./templates/` directory.
+Also, a data YAML. This data YAML is used to generate the final files.
+
+This command prepares the title, description, keywords, and other metadata for the templates.
+Also, it will parse the templates for images, anchors, and text.
+
+| Original                                                                      | Parsed                                                                                                                                          |
+|-------------------------------------------------------------------------------|-------------------------------------------------------------------------------------------------------------------------------------------------|
+| `<html lang="en"><head>`                                                      | `<html lang="en" data-attributes="lang path:lang"><head>`                                                                                       |
+| `<title>Bob</title>`                                                          | `<title data-attributes="title path:title">Bob</title>`                                                                                         |
+| `<meta name="description" content="Bob is a html and html fragment builder">` | `<meta name="description" content="Bob is a html and html fragment builder" data-attributes="description path:meta.description">`               |
+| `<img alt="alt text" title="my title" src="..." `                            | `<img alt="alt text" title="my title" src="..." data-attributes="alt path:img.id1003.alt title path:img.id1003.title src path:img.id1003.src">` |
+| `<a href="https://gitlab.schukai.com/oss/bob">`                              | `<a href="https://gitlab.schukai.com/oss/bob" data-attributes="href path:a.id1004.href">`                                                       |
+| `<p>Bob is a html and html fragment builder</p>`                              | `<p><span data-attributes="text path:p.id1005.text">Bob is a html and html fragment builder</span></p>`                                         |
+
+
+
+
+
+
 
 ## Questions
 
diff --git a/application/source/command.go b/application/source/command.go
new file mode 100644
index 0000000000000000000000000000000000000000..aa2efd03b66bcfa2b2d8112c54e008edaab441fc
--- /dev/null
+++ b/application/source/command.go
@@ -0,0 +1,116 @@
+package main
+
+import (
+	"fmt"
+	html2 "gitlab.schukai.com/oss/bob.git/html"
+	template2 "gitlab.schukai.com/oss/bob.git/template"
+	"gitlab.schukai.com/oss/bob.git/types"
+	"gitlab.schukai.com/oss/libraries/go/application/xflags"
+	"gopkg.in/yaml.v3"
+	"os"
+	"path"
+	"path/filepath"
+)
+
+type Definition struct {
+	Help struct {
+	} `command:"help" call:"PrintHelp" description:"Prints this help message"`
+	Verbose  bool `short:"v" long:"verbose" description:"Show verbose debug information"`
+	Template struct {
+		Prepare struct {
+			Input  string `short:"i" long:"input" description:"Directory with html files to prepare" required:"true"`
+			Output string `short:"o" long:"output" description:"Directory to save prepared html files" required:"true"`
+		} `command:"prepare" description:"Prepare content from a file" call:"PrepareTemplate"`
+	} `command:"template" description:"Template commands"`
+	HTML struct {
+		Generate struct {
+			Input  string `short:"i" long:"input" description:"Directory with prepared html files" required:"true"`
+			Output string `short:"o" long:"output" description:"Directory to save generated template files" required:"true"`
+		} `command:"generate" description:"Generate html files from a file" call:"GenerateHTML"`
+		Sync struct {
+			Specification string `short:"s" long:"specification" description:"Specification file" required:"true"`
+		} `command:"sync" description:"Sync html" call:"SyncHTML"`
+		Cut struct {
+			Specification string `short:"s" long:"specification" description:"Specification file" required:"true"`
+		} `command:"cut" description:"Cut html" call:"CutHTML"`
+	} `command:"html" description:"HTML related commands"`
+}
+
+func (d *Definition) CutHTML(s *xflags.Settings[Definition]) {
+	err := html2.CutHtml(d.HTML.Cut.Specification)
+
+	if err != nil {
+		s.AddError(err)
+	}
+}
+
+func (d *Definition) SyncHTML(s *xflags.Settings[Definition]) {
+
+	err := html2.SyncHtml(d.HTML.Sync.Specification)
+
+	if err != nil {
+		s.AddError(err)
+	}
+}
+func (d *Definition) GenerateHTML(s *xflags.Settings[Definition]) {
+
+	err := filepath.Walk(d.HTML.Generate.Input, func(p string, info os.FileInfo, err error) error {
+
+		if err != nil {
+			return err
+		}
+
+		if info.IsDir() {
+			return nil
+		}
+
+		ext := filepath.Ext(p)
+		if ext != ".yaml" {
+			return nil
+		}
+
+		return html2.GenerateFiles(p, d.HTML.Generate.Output)
+	})
+
+	if err != nil {
+		s.AddError(err)
+	}
+}
+
+func (d *Definition) PrepareTemplate(s *xflags.Settings[Definition]) {
+
+	storage := types.NewPageDataStorage()
+
+	err := filepath.Walk(d.Template.Prepare.Input, func(path string, info os.FileInfo, err error) error {
+
+		if err != nil {
+			return err
+		}
+
+		if info.IsDir() {
+			return nil
+		}
+		return template2.PrepareHtmlFile(path, d.Template.Prepare.Output, storage)
+	})
+
+	if err != nil {
+		s.AddError(err)
+	}
+
+	data, err := yaml.Marshal(storage)
+	if err != nil {
+		s.AddError(err)
+	} else {
+		o := path.Join(d.Template.Prepare.Output, "data.yaml")
+		os.WriteFile(o, data, os.ModePerm)
+	}
+
+	if err != nil {
+		s.AddError(err)
+	}
+
+}
+
+func (d *Definition) PrintHelp(s *xflags.Settings[Definition]) {
+	fmt.Println(s.Help())
+}
diff --git a/application/source/error.go b/application/source/error.go
new file mode 100644
index 0000000000000000000000000000000000000000..81f4ce57e70a83635d57ea81a4f9aa0cba595022
--- /dev/null
+++ b/application/source/error.go
@@ -0,0 +1,13 @@
+package main
+
+import (
+	"fmt"
+	"os"
+)
+
+func checkError(e error) {
+	if e != nil {
+		fmt.Println(e)
+		os.Exit(1)
+	}
+}
diff --git a/application/source/go.mod b/application/source/go.mod
index 0167c86ce779dd9f092c87643e51491203065149..6c8b8ed1aa5fe61648a6c313a43f421d4a414a22 100644
--- a/application/source/go.mod
+++ b/application/source/go.mod
@@ -2,11 +2,33 @@ module gitlab.schukai.com/oss/bob.git
 
 go 1.19
 
+require (
+	github.com/andybalholm/cascadia v1.3.1
+	gitlab.schukai.com/oss/libraries/go/application/xflags v1.13.0
+	gitlab.schukai.com/oss/libraries/go/markup/html v0.2.1
+	golang.org/x/crypto v0.4.0
+	golang.org/x/net v0.4.0
+	gopkg.in/yaml.v3 v3.0.1
+)
+
 require (
 	github.com/davecgh/go-spew v1.1.1 // indirect
+	github.com/fsnotify/fsnotify v1.6.0 // indirect
+	github.com/golang/protobuf v1.5.2 // indirect
+	github.com/imdario/mergo v0.3.13 // indirect
+	github.com/magiconair/properties v1.8.6 // indirect
+	github.com/pelletier/go-toml/v2 v2.0.5 // indirect
 	github.com/pmezard/go-difflib v1.0.0 // indirect
-	github.com/stretchr/testify v1.8.0 // indirect
-	gitlab.schukai.com/oss/libraries/go/application/xflags v1.13.0 // indirect
-	gitlab.schukai.com/oss/libraries/go/utilities/pathfinder v0.3.1 // indirect
-	gopkg.in/yaml.v3 v3.0.1 // indirect
+	github.com/r3labs/diff/v3 v3.0.0 // indirect
+	github.com/stretchr/testify v1.8.1 // indirect
+	github.com/vmihailenco/msgpack v4.0.4+incompatible // indirect
+	github.com/volker-schukai/tokenizer v1.0.0 // indirect
+	gitlab.schukai.com/oss/libraries/go/application/configuration v1.14.0 // indirect
+	gitlab.schukai.com/oss/libraries/go/network/http-negotiation v1.3.0 // indirect
+	gitlab.schukai.com/oss/libraries/go/utilities/data.git v0.2.0 // indirect
+	gitlab.schukai.com/oss/libraries/go/utilities/pathfinder v0.5.0 // indirect
+	golang.org/x/exp v0.0.0-20221023144134-a1e5550cf13e // indirect
+	golang.org/x/sys v0.3.0 // indirect
+	google.golang.org/appengine v1.6.7 // indirect
+	google.golang.org/protobuf v1.28.1 // indirect
 )
diff --git a/application/source/go.sum b/application/source/go.sum
index c7a0b0d7d274b2098b80a508b7233a5293b7761a..734260ea1eeccaefb87bd84d6aa94b647f8166a5 100644
--- a/application/source/go.sum
+++ b/application/source/go.sum
@@ -1,18 +1,88 @@
+github.com/andybalholm/cascadia v1.3.1 h1:nhxRkql1kdYCc8Snf7D5/D3spOX+dBgjA6u8x004T2c=
+github.com/andybalholm/cascadia v1.3.1/go.mod h1:R4bJ1UQfqADjvDa4P6HZHLh/3OxWWEqc0Sk8XGwHqvA=
 github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
 github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
 github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
+github.com/fsnotify/fsnotify v1.6.0 h1:n+5WquG0fcWoWp6xPWfHdbskMCQaFnG6PfBrh1Ky4HY=
+github.com/fsnotify/fsnotify v1.6.0/go.mod h1:sl3t1tCWJFWoRz9R8WJCbQihKKwmorjAbSClcnxKAGw=
+github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
+github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk=
+github.com/golang/protobuf v1.5.2 h1:ROPKBNFfQgOUMifHyP+KYbvpjbdoFNs+aK7DXlji0Tw=
+github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY=
+github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
+github.com/imdario/mergo v0.3.13 h1:lFzP57bqS/wsqKssCGmtLAb8A0wKjLGrve2q3PPVcBk=
+github.com/imdario/mergo v0.3.13/go.mod h1:4lJ1jqUDcsbIECGy0RUJAXNIhg+6ocWgb1ALK2O4oXg=
+github.com/magiconair/properties v1.8.6 h1:5ibWZ6iY0NctNGWo87LalDlEZ6R41TqbbDamhfG/Qzo=
+github.com/magiconair/properties v1.8.6/go.mod h1:y3VJvCyxH9uVvJTWEGAELF3aiYNyPKd5NZ3oSwXrF60=
+github.com/pelletier/go-toml/v2 v2.0.5 h1:ipoSadvV8oGUjnUbMub59IDPPwfxF694nG/jwbMiyQg=
+github.com/pelletier/go-toml/v2 v2.0.5/go.mod h1:OMHamSCAODeSsVrwwvcJOaoN0LIUIaFVNZzmWyNfXas=
 github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
 github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
+github.com/r3labs/diff/v3 v3.0.0 h1:ZhPwNxn9gW5WLPBV9GCYaVbMdLOSmJ0DeKdCiSbOLUI=
+github.com/r3labs/diff/v3 v3.0.0/go.mod h1:wCkTySAiDnZao1sZrVTDIzuzgLZ+cNPGn3LC8DlIg5g=
 github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
 github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
+github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=
+github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA=
+github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
 github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
 github.com/stretchr/testify v1.8.0 h1:pSgiaMZlXftHpm5L7V1+rVB+AZJydKsMxsQBIJw4PKk=
 github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
+github.com/stretchr/testify v1.8.1 h1:w7B6lhMri9wdJUVmEZPGGhZzrYTPvgJArz7wNPgYKsk=
+github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
+github.com/vmihailenco/msgpack v4.0.4+incompatible h1:dSLoQfGFAo3F6OoNhwUmLwVgaUXK79GlxNBwueZn0xI=
+github.com/vmihailenco/msgpack v4.0.4+incompatible/go.mod h1:fy3FlTQTDXWkZ7Bh6AcGMlsjHatGryHQYUTf1ShIgkk=
+github.com/volker-schukai/tokenizer v1.0.0 h1:wF4haFoCodq7lgAk8c+th/DZmpFpL2WVD8wDzAGU1mA=
+github.com/volker-schukai/tokenizer v1.0.0/go.mod h1:LPw7lLIxUnZgeg96818N7IvwLE1x8ya31J/Aa0aCq9M=
+gitlab.schukai.com/oss/libraries/go/application/configuration v1.14.0 h1:cuS7BxTe5pS5iUD6eJKNcErRx6NHGNAGeZx8tOED9pk=
+gitlab.schukai.com/oss/libraries/go/application/configuration v1.14.0/go.mod h1:me1BS/adhucf6h8t2ew0ifaNVio2vunQIYfpofUBbF8=
 gitlab.schukai.com/oss/libraries/go/application/xflags v1.13.0 h1:nTnuGzAOzUTlmrst8tPrLp5EFOwC+6vozsxOcnGVfQk=
 gitlab.schukai.com/oss/libraries/go/application/xflags v1.13.0/go.mod h1:EEYPy5RYR4ahK9J6CTKSLFHUhP+ndHBWVdQMtGCFqDo=
+gitlab.schukai.com/oss/libraries/go/markup/html v0.2.1 h1:d08SBGYHXHWOCJqaLh1Cfh6rOYmHoRJxM63GhF2klCo=
+gitlab.schukai.com/oss/libraries/go/markup/html v0.2.1/go.mod h1:h0+dJUwXfF1QeaBxFiidgxA2I3A9qIPE+zhfs88pKV8=
+gitlab.schukai.com/oss/libraries/go/network/http-negotiation v1.3.0 h1:SZG0BW5ll3WK5ZIOTogjqX8oVHCTxANTDLPxUs7Rnx8=
+gitlab.schukai.com/oss/libraries/go/network/http-negotiation v1.3.0/go.mod h1:RS2rKf5O+rmSBshHLOgjG7dxg5N2MhNYokZOBcuXdX8=
+gitlab.schukai.com/oss/libraries/go/utilities/data.git v0.2.0 h1:JVxMHiA8zFVjJDhNl65XeYrhdMkzB+5dyrBUEZ982WU=
+gitlab.schukai.com/oss/libraries/go/utilities/data.git v0.2.0/go.mod h1:BsR4Y9jsvISplkW6UoLFRGxQX69/AUmP1SXRwWhx31o=
 gitlab.schukai.com/oss/libraries/go/utilities/pathfinder v0.3.1 h1:oyElaqEiyr2XgaE1CYwD8LoeHsuR/vQD/p6k3jYbJFs=
 gitlab.schukai.com/oss/libraries/go/utilities/pathfinder v0.3.1/go.mod h1:UvdD4NAf3gLKYafabJD7e9ZCOetzM9JZ9y4GkZukPVU=
+gitlab.schukai.com/oss/libraries/go/utilities/pathfinder v0.5.0 h1:LsKHjuiEzOS3W5UqtqLmHEDYGVQ7qddf88rmD1HmI4M=
+gitlab.schukai.com/oss/libraries/go/utilities/pathfinder v0.5.0/go.mod h1:UvdD4NAf3gLKYafabJD7e9ZCOetzM9JZ9y4GkZukPVU=
+golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
+golang.org/x/crypto v0.4.0 h1:UVQgzMY87xqpKNgb+kDsll2Igd33HszWHFLmpaRMq/8=
+golang.org/x/crypto v0.4.0/go.mod h1:3quD/ATkf6oY+rnes5c3ExXTbLc8mueNue5/DoinL80=
+golang.org/x/exp v0.0.0-20221023144134-a1e5550cf13e h1:SkwG94eNiiYJhbeDE018Grw09HIN/KB9NlRmZsrzfWs=
+golang.org/x/exp v0.0.0-20221023144134-a1e5550cf13e/go.mod h1:cyybsKvd6eL0RnXn6p/Grxp8F5bW7iYuBgsNCOHpMYE=
+golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks=
+golang.org/x/net v0.0.0-20210916014120-12bc252f5db8/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
+golang.org/x/net v0.1.0 h1:hZ/3BUoy5aId7sCpA/Tc5lt8DkFgdVS2onTpJsZ/fl0=
+golang.org/x/net v0.1.0/go.mod h1:Cx3nUiGt4eDBEyega/BKRp+/AlGL8hYe7U9odMt2Cco=
+golang.org/x/net v0.3.0/go.mod h1:MBQ8lrhLObU/6UmLb4fmbmk5OcyYmqtbGd/9yIeKjEE=
+golang.org/x/net v0.4.0 h1:Q5QPcMlvfxFTAPV0+07Xz/MpK9NTXu2VDUuy0FeMfaU=
+golang.org/x/net v0.4.0/go.mod h1:MBQ8lrhLObU/6UmLb4fmbmk5OcyYmqtbGd/9yIeKjEE=
+golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
+golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20220908164124-27713097b956/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.1.0 h1:kunALQeHf1/185U1i0GOB/fy1IPRDDpuoOOqRReG57U=
+golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.3.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
+golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
+golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
+golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
+golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
+golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
+google.golang.org/appengine v1.6.6/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc=
+google.golang.org/appengine v1.6.7 h1:FZR1q0exgwxzPzp/aF+VccGrSfxfPpkBqjIIEq3ru6c=
+google.golang.org/appengine v1.6.7/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc=
+google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw=
+google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
+google.golang.org/protobuf v1.28.1 h1:d0NfwRgPtno5B1Wa6L2DAG+KivqkdutMf1UhdNx175w=
+google.golang.org/protobuf v1.28.1/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=
 gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
+gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
 gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
+gopkg.in/yaml.v3 v3.0.0/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
 gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
 gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
diff --git a/application/source/html/cut.go b/application/source/html/cut.go
new file mode 100644
index 0000000000000000000000000000000000000000..7f0bfe32414f0aecc375f0f85646bd9b4e2d7a8b
--- /dev/null
+++ b/application/source/html/cut.go
@@ -0,0 +1,200 @@
+package html
+
+import (
+	"github.com/andybalholm/cascadia"
+	"gitlab.schukai.com/oss/bob.git/types"
+	"gitlab.schukai.com/oss/libraries/go/markup/html/engine"
+	"golang.org/x/net/html"
+	"gopkg.in/yaml.v3"
+	"os"
+	"path/filepath"
+	"strings"
+)
+
+func CutHtml(p string) error {
+
+	content, err := os.ReadFile(p)
+	if err != nil {
+		return err
+	}
+
+	currentDir, _ := os.Getwd()
+	os.Chdir(filepath.Dir(p))
+	defer os.Chdir(currentDir)
+
+	specification := types.SnippetsSpecification{}
+
+	if err := yaml.Unmarshal(content, &specification); err != nil {
+		return err
+	}
+
+	sourceFiles := make(map[string]*html.Node)
+
+	for _, r := range specification.Snippets {
+
+		source := r.Source
+
+		absSource, err := filepath.Abs(source)
+		if err != nil {
+			return err
+		}
+
+		if sourceFiles[absSource], err = readHTML(absSource); err != nil {
+			return err
+		}
+	}
+
+	for _, r := range specification.Snippets {
+
+		source := r.Source
+		destination := r.Destination
+
+		absSource, err := filepath.Abs(source)
+		if err != nil {
+			return err
+		}
+
+		sourceNode, ok := sourceFiles[absSource]
+		if !ok {
+			continue
+		}
+
+		replacedNodes, err := replaceNodes(sourceNode, r.Replacement)
+		if err != nil {
+			return err
+		}
+
+		err = setAttributes(replacedNodes, r.Attributes)
+		if err != nil {
+			return err
+		}
+
+		selectors := r.Selector
+		query, err := cascadia.Compile(selectors)
+		if err != nil {
+			return err
+		}
+
+		snippetNode := query.MatchFirst(replacedNodes)
+
+		absDestination, err := filepath.Abs(destination)
+		if err != nil {
+			return err
+		}
+
+		fp, err := os.Create(absDestination)
+		if err != nil {
+			return err
+		}
+
+		err = html.Render(fp, snippetNode)
+		err2 := fp.Close()
+		if err2 != nil {
+			return err2
+		}
+
+		if err != nil {
+			return err
+		}
+
+	}
+
+	return nil
+
+}
+
+func setAttributes(n *html.Node, attributes []types.Attributes) error {
+
+	for _, a := range attributes {
+
+		sel, err := cascadia.Compile(a.Selector)
+		if err != nil {
+			return err
+		}
+
+		for _, h := range sel.MatchAll(n) {
+			removeAttribute(h.Attr, a.Name)
+			h.Attr = append(h.Attr, html.Attribute{Key: a.Name, Val: a.Value})
+		}
+
+	}
+
+	return nil
+
+}
+
+func removeAttribute(attrs []html.Attribute, key string) []html.Attribute {
+
+	var result []html.Attribute
+
+	for _, attr := range attrs {
+		if attr.Key == key {
+			continue
+		}
+
+		result = append(result, attr)
+	}
+
+	return result
+}
+
+func replaceNodes(n *html.Node, replacements []types.ContentReplacement) (*html.Node, error) {
+
+	ret := engine.CloneNode(n)
+
+	for _, r := range replacements {
+
+		doc, err := html.Parse(strings.NewReader(r.Content))
+		if err != nil {
+			return nil, err
+		}
+
+		nodeList := []html.Node{}
+
+		sel, err := cascadia.Compile("head")
+		if err != nil {
+			return nil, err
+		}
+
+		head := sel.MatchAll(doc)
+		for _, h := range head {
+			if h.FirstChild == nil {
+				continue
+			}
+
+			for c := h.FirstChild; c != nil; c = c.NextSibling {
+				nodeList = append(nodeList, *c)
+			}
+		}
+
+		sel, err = cascadia.Compile("body")
+		if err != nil {
+			return nil, err
+		}
+		for _, h := range sel.MatchAll(doc) {
+			if h.FirstChild == nil {
+				continue
+			}
+
+			for c := h.FirstChild; c != nil; c = c.NextSibling {
+				nodeList = append(nodeList, *c)
+			}
+		}
+
+		sel, err = cascadia.Compile(r.Selector)
+		if err != nil {
+			return nil, err
+		}
+
+		for _, h := range sel.MatchAll(ret) {
+			for _, node := range nodeList {
+				h.Parent.InsertBefore(engine.CloneNode(&node), h)
+			}
+			h.Parent.RemoveChild(h)
+		}
+
+	}
+
+	return ret, nil
+
+}
diff --git a/application/source/html/generate.go b/application/source/html/generate.go
new file mode 100644
index 0000000000000000000000000000000000000000..a8a5c6541401950ae13eae0b251f35de858e1968
--- /dev/null
+++ b/application/source/html/generate.go
@@ -0,0 +1,90 @@
+package html
+
+import (
+	"gitlab.schukai.com/oss/bob.git/types"
+	"gitlab.schukai.com/oss/libraries/go/markup/html/engine"
+	"gopkg.in/yaml.v3"
+	"os"
+	"path"
+	"strings"
+)
+
+func GenerateFiles(dataPath, out string) error {
+
+	dir := path.Dir(dataPath)
+
+	yamlFile, err := os.ReadFile(dataPath)
+	if err != nil {
+		return err
+	}
+
+	storage := types.NewPageDataStorage()
+	if err := yaml.Unmarshal(yamlFile, storage); err != nil {
+		return err
+	}
+
+	for name, page := range storage {
+		p := path.Join(dir, name)
+		html, err := Generate(page, p)
+		if err != nil {
+			return err
+		}
+
+		outFile := path.Join(out, name)
+
+		err = os.WriteFile(outFile, []byte(html), 0644)
+		if err != nil {
+			return err
+		}
+
+	}
+
+	return nil
+}
+
+func Generate(data *types.PageData, name string) (string, error) {
+
+	dataset := make(map[any]any)
+	dataset["lang"] = data.Lang
+	dataset["title"] = data.Title
+	dataset["meta"] = make(map[any]any)
+	for k, v := range data.Meta {
+		dataset["meta"].(map[any]any)[k] = v
+	}
+	dataset["images"] = make(map[any]any, 0)
+	for _, v := range data.Images {
+		dataset["images"].(map[any]any)[v.Id] = map[any]any{
+			"source": v.Source,
+			"alt":    v.Alt,
+			"title":  v.Title,
+			"id":     v.Id,
+		}
+	}
+
+	dataset["anchors"] = make(map[any]any, 0)
+	for _, v := range data.Anchors {
+		dataset["anchors"].(map[any]any)[v.Id] = map[any]any{
+			"href":     v.Href,
+			"hreflang": v.HrefLang,
+			"title":    v.Title,
+			"id":       v.Id,
+		}
+	}
+
+	dataset["text"] = make(map[any]any, 0)
+	for _, v := range data.Text {
+		dataset["text"].(map[any]any)[v.Id] = map[any]any{"text": v.Text}
+	}
+
+	e := engine.New(dataset)
+
+	template, err := os.ReadFile(name)
+	if err != nil {
+		return "", err
+	}
+
+	stringWriter := &strings.Builder{}
+	e.ProcessHtml(stringWriter, strings.NewReader(string(template)))
+
+	return stringWriter.String(), nil
+}
diff --git a/application/source/html/sync.go b/application/source/html/sync.go
new file mode 100644
index 0000000000000000000000000000000000000000..f4486e38bee3001e1c525b1925f821ac965d18de
--- /dev/null
+++ b/application/source/html/sync.go
@@ -0,0 +1,201 @@
+package html
+
+import (
+	"fmt"
+	"github.com/andybalholm/cascadia"
+	"gitlab.schukai.com/oss/bob.git/types"
+	"gitlab.schukai.com/oss/libraries/go/markup/html/engine"
+	"golang.org/x/net/html"
+	"gopkg.in/yaml.v3"
+	"os"
+	"path/filepath"
+)
+
+type Specification struct {
+	Selector string
+}
+
+func readHTML(p string) (*html.Node, error) {
+	htmlFile, err := os.Open(p)
+	if err != nil {
+		return nil, err
+	}
+	defer htmlFile.Close()
+
+	return html.Parse(htmlFile)
+}
+
+func SyncHtml(p string) error {
+
+	content, err := os.ReadFile(p)
+	if err != nil {
+		return err
+	}
+
+	currentDir, _ := os.Getwd()
+	os.Chdir(filepath.Dir(p))
+	defer os.Chdir(currentDir)
+
+	specification := types.SyncSpecification{}
+
+	if err := yaml.Unmarshal(content, &specification); err != nil {
+		return err
+	}
+
+	sourceFiles := make(map[string]*html.Node)
+	destinationFiles := make(map[string]*html.Node)
+	sourceDestination := make(map[string][]string)
+
+	for _, r := range specification.Sync {
+
+		source := r.Source
+		destination := r.Destination
+		exclude := r.Destination.Exclude
+
+		absSource, err := filepath.Abs(source.Path)
+		if err != nil {
+			return err
+		}
+
+		if err != nil {
+			return err
+		}
+
+		if sourceFiles[absSource], err = readHTML(absSource); err != nil {
+			return err
+		}
+
+		for _, d := range destination.Path {
+
+			d, err := filepath.Abs(d)
+			if err != nil {
+				return err
+			}
+
+			fileinfo, err := os.Stat(d)
+			if err != nil {
+				return err
+			}
+
+			if fileinfo.IsDir() {
+				filepath.Walk(d, func(pp string, info os.FileInfo, err error) error {
+					if err != nil {
+						return err
+					}
+					if info.IsDir() {
+						return nil
+					}
+
+					if exclude != nil {
+						for _, e := range exclude {
+							e, err := filepath.Abs(e)
+							if err != nil {
+								return err
+							}
+							if e == pp {
+								return nil
+							}
+						}
+					}
+
+					ext := filepath.Ext(pp)
+					if ext == ".html" {
+
+						var dd *html.Node
+						if dd, err = readHTML(pp); err != nil {
+							return err
+						}
+
+						destinationFiles[pp] = dd
+						sourceDestination[absSource] = append(sourceDestination[absSource], pp)
+
+					}
+
+					return nil
+				})
+			} else if filepath.Ext(d) == ".html" {
+
+				if exclude != nil {
+					for _, e := range exclude {
+						e, err := filepath.Abs(e)
+						if err != nil {
+							return err
+						}
+						if e == d {
+							return nil
+						}
+					}
+				}
+
+				var dd *html.Node
+				if dd, err = readHTML(d); err != nil {
+					return err
+				}
+
+				destinationFiles[d] = dd
+				sourceDestination[absSource] = append(sourceDestination[absSource], d)
+
+			}
+
+		}
+
+		for _, r := range specification.Sync {
+			source := r.Source
+			absSource, err := filepath.Abs(source.Path)
+			if err != nil {
+				return err
+			}
+			sourceSelector := source.Selector
+
+			query, err := cascadia.Compile(sourceSelector)
+			if err != nil {
+				return err
+			}
+
+			sourceNode := query.MatchFirst(sourceFiles[absSource])
+
+			dp := sourceDestination[absSource]
+			for _, d := range dp {
+				destinationSelector := r.Destination.Selector
+				if destinationSelector == "" {
+					destinationSelector = sourceSelector
+				}
+
+				query, err := cascadia.Compile(destinationSelector)
+				if err != nil {
+					return err
+				}
+				destinationData := query.MatchFirst(destinationFiles[d])
+
+				if destinationData == nil {
+					return fmt.Errorf("could not find selector %s in %s", destinationSelector, d)
+				}
+
+				n := engine.CloneNode(sourceNode)
+				destinationData.Parent.InsertBefore(n, destinationData)
+				destinationData.Parent.RemoveChild(destinationData)
+			}
+
+		}
+
+		for p, d := range destinationFiles {
+			fp, err := os.Create(p)
+			if err != nil {
+				return err
+			}
+			err = html.Render(fp, d)
+			err2 := fp.Close()
+			if err2 != nil {
+				return err2
+			}
+
+			if err != nil {
+				return err
+			}
+
+		}
+
+	}
+
+	return nil
+}
diff --git a/application/source/main.go b/application/source/main.go
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..48433a389bae8c8517ab41c265337cd4f74de90a 100644
--- a/application/source/main.go
+++ b/application/source/main.go
@@ -0,0 +1,30 @@
+package main
+
+import (
+	"fmt"
+	"gitlab.schukai.com/oss/libraries/go/application/xflags"
+	"os"
+)
+
+func main() {
+
+	var settings *xflags.Settings[Definition]
+
+	settings = xflags.New(os.Args[0], Definition{})
+	settings.Parse(os.Args[1:])
+	settings.Execute()
+
+	if settings.HasErrors() {
+		for _, err := range settings.Errors() {
+			fmt.Println(err)
+		}
+
+		os.Exit(1)
+	} else {
+		if settings.WasExecuted() {
+			os.Exit(0)
+		}
+		os.Exit(1)
+	}
+
+}
diff --git a/application/source/template/prepare.go b/application/source/template/prepare.go
new file mode 100644
index 0000000000000000000000000000000000000000..a887056f3644d273fc140b05dcda287aec400988
--- /dev/null
+++ b/application/source/template/prepare.go
@@ -0,0 +1,304 @@
+package template
+
+import (
+	"github.com/andybalholm/cascadia"
+	"gitlab.schukai.com/oss/bob.git/types"
+	"gitlab.schukai.com/oss/bob.git/util"
+	"golang.org/x/net/html"
+	"golang.org/x/net/html/atom"
+	"path"
+	"strings"
+)
+
+const attributePrefix = "data-"
+const attributeAttributes = "data-attributes"
+const attributeReplace = "data-replace"
+
+func removeAttribute(attrs []html.Attribute, key string) []html.Attribute {
+
+	var result []html.Attribute
+
+	for _, attr := range attrs {
+		if attr.Key == key {
+			continue
+		}
+
+		result = append(result, attr)
+	}
+
+	return result
+}
+
+//func setDataAttribute(node *html.Node, name, attribute, instruction string) {
+//	node.Attr = removeAttribute(node.Attr, name)
+//	node.Attr = append(node.Attr, html.Attribute{Key: name, Val: attribute + " " + instruction})
+//}
+
+func setDataAttributesAttribute(node *html.Node, name, attribute, instruction string) {
+
+	value := util.GetAttribute(node.Attr, attributeAttributes)
+	if value != "" {
+		l := strings.Split(value, ",")
+		m := make(map[string]string)
+		for _, v := range l {
+			v = strings.TrimSpace(v)
+			x := strings.Index(v, " ")
+			if x > 0 {
+				a := v[:x]
+				b := v[x+1:]
+
+				if a != attribute {
+					m[a] = b
+				}
+			}
+		}
+		value = ""
+		for k, v := range m {
+			if value != "" {
+				value += ","
+			}
+			value += k + " " + v
+		}
+	}
+
+	node.Attr = removeAttribute(node.Attr, attributeAttributes)
+
+	if value != "" {
+		value += ","
+	}
+	value += attribute + " " + instruction
+	node.Attr = append(node.Attr, html.Attribute{Key: name, Val: value})
+
+}
+
+func prepateMeta(node *html.Node, attrKey, attrValue string, storage *types.PageData) {
+	sel, err := cascadia.Parse("meta[" + attrKey + "=" + attrValue + "]")
+	if err != nil {
+		return
+	}
+
+	meta := cascadia.Query(node, sel)
+	if meta == nil {
+		return
+	}
+
+	setDataAttributesAttribute(meta, attributeAttributes, "content", "path:meta."+attrValue)
+
+	storage.Meta[attrValue] = util.GetAttribute(meta.Attr, "content")
+
+}
+
+func prepareLanguage(node *html.Node, storage *types.PageData) {
+
+	selector, err := cascadia.Parse("html")
+	if err != nil {
+		return
+	}
+
+	n := cascadia.Query(node, selector)
+	if n == nil {
+		return
+	}
+
+	setDataAttributesAttribute(n, attributeAttributes, "lang", "path:lang")
+
+	lang := util.GetAttribute(n.Attr, "lang")
+	if lang == "" {
+		lang = "en"
+	}
+
+	storage.Lang = lang
+
+}
+
+func prepareTitle(node *html.Node, storage *types.PageData) {
+
+	selector, err := cascadia.Parse("title")
+	if err != nil {
+		return
+	}
+
+	n := cascadia.Query(node, selector)
+	if n == nil {
+		return
+	}
+
+	n.Attr = removeAttribute(node.Attr, attributeReplace)
+	n.Attr = append(node.Attr, html.Attribute{Key: attributeReplace, Val: "path:title"})
+
+	title := ""
+	for c := n.FirstChild; c != nil; c = c.NextSibling {
+		if c.Type == html.TextNode {
+			title += c.Data
+		}
+	}
+
+	storage.Title = title
+
+}
+
+func prepareAnchors(node *html.Node, storage *types.PageData) {
+	selector, err := cascadia.Parse("a")
+	if err != nil {
+		return
+	}
+
+	list := cascadia.QueryAll(node, selector)
+	if list == nil {
+		return
+	}
+
+	for _, n := range list {
+
+		title := util.GetAttribute(n.Attr, "title")
+		hreflang := util.GetAttribute(n.Attr, "hreflang")
+		href := util.GetAttribute(n.Attr, "href")
+
+		id := util.GetOrCreateId(n, title+hreflang+href)
+		if id == "" {
+			id, _ = util.RandomString(8)
+			n.Attr = removeAttribute(n.Attr, "id")
+			n.Attr = append(n.Attr, html.Attribute{Key: "id", Val: id})
+		}
+
+		setDataAttributesAttribute(n, attributeAttributes, "href", "path:anchors."+id+".href")
+		setDataAttributesAttribute(n, attributeAttributes, "title", "path:anchors."+id+".title")
+		setDataAttributesAttribute(n, attributeAttributes, "hreflang", "path:anchors."+id+".hreflang")
+
+		storage.Anchors = append(storage.Anchors, types.Anchor{
+			Id:       id,
+			Title:    title,
+			HrefLang: hreflang,
+			Href:     href,
+		})
+
+	}
+}
+
+func prepareImages(node *html.Node, storage *types.PageData) {
+
+	selector, err := cascadia.Parse("img")
+	if err != nil {
+		return
+	}
+
+	list := cascadia.QueryAll(node, selector)
+	if list == nil {
+		return
+	}
+
+	for _, n := range list {
+
+		alt := util.GetAttribute(n.Attr, "alt")
+		title := util.GetAttribute(n.Attr, "title")
+		source := util.GetAttribute(n.Attr, "src")
+
+		id := util.GetOrCreateId(n, alt+title+source)
+		if id == "" {
+			id, _ = util.RandomString(8)
+			n.Attr = removeAttribute(n.Attr, "id")
+			n.Attr = append(n.Attr, html.Attribute{Key: "id", Val: id})
+		}
+
+		setDataAttributesAttribute(n, attributeAttributes, "src", "path:content."+id+".src")
+		setDataAttributesAttribute(n, attributeAttributes, "alt", "path:content."+id+".alt")
+		setDataAttributesAttribute(n, attributeAttributes, "title", "path:content."+id+".title")
+
+		storage.Images = append(storage.Images, types.Image{
+			Id:     id,
+			Alt:    alt,
+			Title:  title,
+			Source: source,
+		})
+
+	}
+
+}
+
+func prepareTextNodes(node *html.Node, storage *types.PageData) {
+
+	selector, err := cascadia.Parse("body")
+	if err != nil {
+		return
+	}
+
+	body := cascadia.Query(node, selector)
+	if body == nil {
+		return
+	}
+
+	runNodes(body, storage)
+
+}
+
+func runNodes(n *html.Node, storage *types.PageData) {
+	if n.Type == html.TextNode {
+
+		content := strings.TrimSpace(n.Data)
+		if content == "" {
+			return
+		}
+
+		id, err := util.BuildTextKey(content)
+		if err != nil {
+			id = util.GetNextId()
+		}
+
+		parent := n.Parent
+		span := &html.Node{
+			Type: html.ElementNode,
+			Data: atom.Span.String(),
+			Attr: []html.Attribute{
+				{
+					Key: "id",
+					Val: id,
+				},
+				{
+					Key: "data-replace-self",
+					Val: "path:text." + id + ".text",
+				},
+			},
+		}
+		parent.InsertBefore(span, n)
+		parent.RemoveChild(n)
+
+		span.AppendChild(n)
+
+		storage.Text = append(storage.Text, types.Text{
+			Id:   id,
+			Text: content,
+		})
+
+		return
+	}
+
+	for c := n.FirstChild; c != nil; c = c.NextSibling {
+		runNodes(c, storage)
+	}
+
+}
+
+func PrepareHtmlFile(from, to string, storage types.PageDataStorage) error {
+	node, err := util.LoadHtml(from)
+	if err != nil {
+		return err
+	}
+
+	p := path.Base(from)
+	pd := types.NewPageData()
+	storage[p] = pd
+
+	prepareLanguage(node, pd)
+	prepareTitle(node, pd)
+	prepateMeta(node, "name", "description", pd)
+	prepateMeta(node, "name", "keywords", pd)
+	prepateMeta(node, "name", "author", pd)
+
+	prepareImages(node, pd)
+	prepareAnchors(node, pd)
+	prepareTextNodes(node, pd)
+
+	to = path.Join(to, path.Base(from))
+	return util.SaveHtml(to, node)
+
+}
diff --git a/application/source/types/page-data.go b/application/source/types/page-data.go
new file mode 100644
index 0000000000000000000000000000000000000000..0432fea76c4fcb3c410960ce8f1fb71d8d73d4da
--- /dev/null
+++ b/application/source/types/page-data.go
@@ -0,0 +1,44 @@
+package types
+
+type Text struct {
+	Text string `yaml:"text"`
+	Id   string `yaml:"id"`
+}
+
+type Image struct {
+	Id     string `yaml:"id"`
+	Source string `yaml:"source"`
+	Alt    string `yaml:"alt"`
+	Title  string `yaml:"title"`
+}
+
+type Anchor struct {
+	Id       string `yaml:"id"`
+	Href     string `yaml:"href"`
+	HrefLang string `yaml:"hreflang"`
+	Title    string
+}
+
+type PageData struct {
+	Lang    string            `yaml:"lang"`
+	Title   string            `yaml:"title"`
+	Meta    map[string]string `yaml:"meta"`
+	Images  []Image           `yaml:"images"`
+	Anchors []Anchor          `yaml:"anchors"`
+	Text    []Text            `yaml:"text"`
+}
+
+func NewPageData() *PageData {
+	pd := &PageData{}
+	pd.Meta = make(map[string]string)
+	return pd
+}
+
+type PageDataStorage map[string]*PageData
+
+func NewPageDataStorage() PageDataStorage {
+	var storage PageDataStorage
+	storage = PageDataStorage{}
+	return storage
+
+}
diff --git a/application/source/types/snippets-specification.go b/application/source/types/snippets-specification.go
new file mode 100644
index 0000000000000000000000000000000000000000..0ff0c8ea43e6f96817171a0ca9ba839dad4dda3c
--- /dev/null
+++ b/application/source/types/snippets-specification.go
@@ -0,0 +1,24 @@
+package types
+
+type Snippet struct {
+	Selector    string               `yaml:"selector"`
+	Source      string               `yaml:"source"`
+	Destination string               `yaml:"destination"`
+	Attributes  []Attributes         `yaml:"attribute"`
+	Replacement []ContentReplacement `yaml:"replacement"`
+}
+
+type ContentReplacement struct {
+	Selector string `yaml:"selector"`
+	Content  string `yaml:"content"`
+}
+
+type SnippetsSpecification struct {
+	Snippets []Snippet `yaml:"snippet"`
+}
+
+type Attributes struct {
+	Selector string `yaml:"selector"`
+	Name     string `yaml:"name"`
+	Value    string `yaml:"value"`
+}
diff --git a/application/source/types/sync-specification.go b/application/source/types/sync-specification.go
new file mode 100644
index 0000000000000000000000000000000000000000..bafd4b8cbd7199022e658a6170fc41cbd5d3038b
--- /dev/null
+++ b/application/source/types/sync-specification.go
@@ -0,0 +1,50 @@
+package types
+
+import "gopkg.in/yaml.v3"
+
+type PathOrList []string
+
+//	func (p PathOrList) MarshalYAML() (interface{}, error) {
+//		return yaml.Marshal(p)
+//	}
+func (p *PathOrList) UnmarshalYAML(value *yaml.Node) error {
+
+	var multi []string
+	err := value.Decode(&multi)
+	if err != nil {
+		var single string
+		err := value.Decode(&single)
+		if err != nil {
+			return err
+		}
+		*p = []string{single}
+	} else {
+		*p = multi
+	}
+	return nil
+}
+
+//func (p *PathOrList) UnmarshalYAML(b interface{}) error {
+//	var s string
+//	if err := yaml.Unmarshal(b, &s); err != nil {
+//		return err
+//	}
+//
+//	return nil
+//}
+
+type Sync struct {
+	Source struct {
+		Selector string `yaml:"selector"`
+		Path     string `yaml:"path"`
+	} `yaml:"source"`
+	Destination struct {
+		Selector string     `yaml:"selector"`
+		Path     PathOrList `yaml:"path"`
+		Exclude  []string   `yaml:"exclude"`
+	} `yaml:"destination"`
+}
+
+type SyncSpecification struct {
+	Sync []Sync `yaml:"sync"`
+}
diff --git a/application/source/util/html.go b/application/source/util/html.go
new file mode 100644
index 0000000000000000000000000000000000000000..1c264710278d05f96dd0e17c4f50898c34accc61
--- /dev/null
+++ b/application/source/util/html.go
@@ -0,0 +1,93 @@
+package util
+
+import (
+	"errors"
+	"golang.org/x/net/html"
+	"os"
+	"strconv"
+)
+
+func LoadHtml(p string) (*html.Node, error) {
+	f, err := os.Open(p)
+	if err != nil {
+		return nil, err
+	}
+	defer f.Close()
+
+	return html.Parse(f)
+
+}
+
+func GetAttribute(attrs []html.Attribute, key string) string {
+	for _, attr := range attrs {
+		if attr.Key == key {
+			return attr.Val
+		}
+	}
+
+	return ""
+}
+
+var internalIDCounter int = 999
+
+func GetNextId() string {
+	internalIDCounter++
+	return "id" + strconv.Itoa(internalIDCounter)
+
+}
+
+func GetOrCreateId(node *html.Node, text string) string {
+
+	var err error
+
+	nodeId := GetAttribute(node.Attr, "id")
+	if nodeId != "" {
+		return nodeId
+	}
+
+	nodeId, err = BuildTextKey(text)
+	if err != nil {
+		nodeId = GetNextId()
+	}
+
+	node.Attr = append(node.Attr, html.Attribute{Key: "id", Val: nodeId})
+	return nodeId
+
+}
+
+func ReplaceAttribute(node *html.Node, key, value string) {
+	for i, attr := range node.Attr {
+		if attr.Key != key {
+			continue
+		}
+
+		node.Attr[i].Val = value
+		return
+	}
+
+	node.Attr = append(node.Attr, html.Attribute{Key: key, Val: value})
+
+}
+
+func SaveHtml(p string, node *html.Node) error {
+
+	var f *os.File
+	var err error
+
+	_, err = os.Stat(p)
+	if errors.Is(err, os.ErrNotExist) {
+		f, err = os.Create(p)
+	} else if err != nil {
+		return err
+	} else {
+		os.Remove(p)
+		f, err = os.Create(p)
+		if err != nil {
+			return err
+		}
+	}
+
+	defer f.Close()
+	return html.Render(f, node)
+
+}
diff --git a/application/source/util/id.go b/application/source/util/id.go
new file mode 100644
index 0000000000000000000000000000000000000000..cef7728aa3a7994f149b81bbecb6ec9ca3c0d596
--- /dev/null
+++ b/application/source/util/id.go
@@ -0,0 +1,92 @@
+package util
+
+import (
+	"encoding/base64"
+	"golang.org/x/crypto/bcrypt"
+	"hash/fnv"
+	"math/rand"
+	"regexp"
+	"strconv"
+	"strings"
+)
+
+const tempStringMask = "GAEKEEPHIENOHJOHEOJH" // random string to avoid collision with other text nodes
+const keyDelimiter = "-"
+
+// NewSecret creates a new secret
+func NewSecret() (string, error) {
+	return NewSecretWithLength(32)
+}
+
+// NewSecretWithLength creates a new secret for a given length
+func NewSecretWithLength(length int) (string, error) {
+	return RandomString(length)
+}
+
+func randomBytes(len int) ([]byte, error) {
+	b := make([]byte, len)
+
+	if _, err := rand.Read(b); err != nil {
+		return nil, err
+	}
+	return b, nil
+}
+
+func RandomString(length int) (string, error) {
+	b, err := randomBytes(length)
+	if err != nil {
+		return "", err
+	}
+
+	s := base64.URLEncoding.EncodeToString(b)
+
+	return cryptID(s, length)
+
+}
+
+func cryptID(t string, length int) (string, error) {
+	hash, err := bcrypt.GenerateFromPassword([]byte(t), bcrypt.DefaultCost)
+	if err != nil {
+		return "", err
+	}
+
+	r := strings.ToUpper(string(hash[len(hash)-length-1 : len(hash)-1]))
+	return r, nil
+}
+
+func hashString(s string) string {
+	h := fnv.New32a()
+	h.Write([]byte(s))
+	return strconv.Itoa(int(h.Sum32()))
+}
+
+func BuildTextKey(txt string) (string, error) {
+
+	txt = strings.TrimSpace(txt)
+	txt = strings.ToLower(txt)
+
+	txt = strings.ReplaceAll(txt, keyDelimiter, tempStringMask)
+	reg, err := regexp.Compile("[^a-z0-9]+")
+	if err != nil {
+		return "", err
+	}
+	newStr := reg.ReplaceAllString(txt, keyDelimiter)
+	newStr = strings.ReplaceAll(newStr, tempStringMask, keyDelimiter)
+
+	newStr = strings.Trim(newStr, keyDelimiter)
+
+	if len(newStr) > 20 {
+		newStr = newStr[:20] + keyDelimiter + hashString(newStr)
+	}
+
+	c := strings.TrimSpace(newStr)
+	if c == "" {
+		return "", nil
+	}
+
+	if len(c) < 2 {
+		return "", nil
+	}
+
+	return c, nil
+}
diff --git a/development/examples/example1/config/snippet.yaml b/development/examples/example1/config/snippet.yaml
new file mode 100644
index 0000000000000000000000000000000000000000..bb21f81000bdbae6dfdb8f1260594e3536451d84
--- /dev/null
+++ b/development/examples/example1/config/snippet.yaml
@@ -0,0 +1,13 @@
+snippet:
+  -
+    source: ../template/test.html
+    selector: 'monster-state'
+    destination: ../snippets/meta/container.html
+    attribute:
+      - selector: 'li'
+        name: 'data-state'
+        value: 'monster'
+    replacement:
+      -
+        selector: 'li>span'
+        content: '!!!!!!!!!!!!!!!!!!'
diff --git a/development/examples/example1/config/spec1.yaml b/development/examples/example1/config/spec1.yaml
new file mode 100644
index 0000000000000000000000000000000000000000..b55ca45c847df4ec2101aab84dd1a5066e1e1957
--- /dev/null
+++ b/development/examples/example1/config/spec1.yaml
@@ -0,0 +1,20 @@
+sync:
+
+  - source:
+      path: '../original/test1.html'
+      selector: '#mainscript'
+    destination:
+      path: '../original/'
+      exclude:
+        - ../original/test1.html
+        
+  - source:
+      path: '../original/test1.html'
+      selector: '.deco'
+    destination:
+      path: '../original/'
+      exclude:
+        - ../original/test1.html
+     
+
+     
diff --git a/development/examples/example1/html/test.html b/development/examples/example1/html/test.html
new file mode 100644
index 0000000000000000000000000000000000000000..b697ce002ebbc78cc42b154ddf246828bc25fa61
--- /dev/null
+++ b/development/examples/example1/html/test.html
@@ -0,0 +1,69 @@
+<!DOCTYPE html><html lang="en"><head>
+
+    <style>
+        *:not(:defined) {
+            visibility: hidden;
+        }
+    </style>
+
+    <meta charset="utf-8"/>
+    <meta name="viewport" content="width=device-width, initial-scale=1"/>
+
+    <meta name="robots" content="noindex"/>
+
+    <link rel="icon" type="image/x-icon" href="/asset/icon/favicon.svg"/>
+    <meta name="theme-color" content="#c10000"/>
+    <link rel="apple-touch-icon" sizes="180x180" href="/asset/icon/apple-touch-icon.png"/>
+    <link rel="icon" type="image/png" sizes="32x32" href="/asset/icon/favicon-32x32.png"/>
+    <link rel="icon" type="image/png" sizes="16x16" href="/asset/icon/favicon-16x16.png"/>
+    <link rel="mask-icon" href="/asset/icon/safari-pinned-tab.svg" color="#fd1d1d"/>
+    <meta name="msapplication-TileColor" content="#fd1d1d"/>
+    <meta name="msapplication-TileImage" content="/asset/icon/mstile-144x144.png"/>
+
+    <title>Bad Request</title>
+    <meta name="description" content="The request was malformed or invalid."/>
+    <meta name="author" content="schukai GmbH"/>
+
+    <link rel="icon" href="/favicon.ico"/>
+    <link rel="icon" href="/favicon.svg" type="image/svg+xml"/>
+    <link rel="apple-touch-icon" href="/apple-touch-icon.png"/>
+
+    <script src="/script/main.mjs" type="module"></script>
+</head>
+
+<body>
+<header>
+    <div class="gradient"></div>
+</header>
+
+<monster-state>
+    <img width="16" height="16" alt="tick" title="yes" src="data:image/gif;base64,R0lGODdhEAAQAMwAAPj7+FmhUYjNfGuxYYDJdYTIeanOpT+DOTuANXi/bGOrWj6CONzv2sPjv2Cm
+  V1unU4zPgI/Sg6DJnJ3ImTh8Mtbs00aNP1CZSGy0YqLEn47RgXW8amasW7XWsmmvX2iuXiwAAAAAEAAQAAAFVyAgjmRpnihqGCkpDQ
+  PbGkNUOFk6DZqgHCNGg2T4QAQBoIiRSAwBE4VA4FACKgkB5NGReASFZEmxsQ0whPDi9BiACYQAInXhwOUtgCUQoORFCGt/g4QAIQA7" id="tickyesdata-image-gi-4013311193"/>
+    <h1 class="deco">Bad Request</h1>
+    <p>The request was incorrect, the server could not process it.</p><p>
+</p><div class="infobox">
+    <div>
+
+        <ul>
+
+            <li>Try submitting your<a id="yes-a-html" href="/b.html" title="Yes" hreflang="">request</a> again (sometimes this helps).</li>
+            <li>Contact support if you continue to have problems.</li>
+
+            <li>If you received this message as a result of a request to the server API, then check the structure
+                against the documentation.</li>
+
+
+        </ul>
+
+        <p>You   can   try    the following steps:</p>
+        
+    </div>
+</div>
+
+
+</monster-state>
+
+
+
+</body></html>
\ No newline at end of file
diff --git a/development/examples/example1/original/test1.html b/development/examples/example1/original/test1.html
new file mode 100644
index 0000000000000000000000000000000000000000..5b7e9acad8157b903b19feb079248e71a1c0b3e2
--- /dev/null
+++ b/development/examples/example1/original/test1.html
@@ -0,0 +1,71 @@
+<!DOCTYPE html><html lang="de"><head>
+
+    <style>
+        *:not(:defined) {
+            visibility: hidden;
+        }
+    </style>
+
+    <meta charset="utf-8"/>
+    <meta name="viewport" content="width=device-width, initial-scale=1"/>
+
+    <meta name="robots" content="noindex,noarchive"/>
+
+    <link rel="icon" type="image/x-icon" href="/asset/icon/favicon.svg"/>
+    <meta name="theme-color" content="#c10000"/>
+    <link rel="apple-touch-icon" sizes="180x180" href="/asset/icon/apple-touch-icon.png"/>
+    <link rel="icon" type="image/png" sizes="32x32" href="/asset/icon/favicon-32x32.png"/>
+    <link rel="icon" type="image/png" sizes="16x16" href="/asset/icon/favicon-16x16.png"/>
+    <link rel="mask-icon" href="/asset/icon/safari-pinned-tab.svg" color="#fd1d1d"/>
+    <meta name="msapplication-TileColor" content="#fd1d1d"/>
+    <meta name="msapplication-TileImage" content="/asset/icon/mstile-144x144.png"/>
+
+    <title>Bad Request ME</title>
+    <meta name="description" content="The request was malformed or invalid."/>
+    <meta name="author" content="schukai GmbH"/>
+
+    <link rel="icon" href="/favicon.ico"/>
+    <link rel="icon" href="/favicon.svg" type="image/svg+xml"/>
+    <link rel="apple-touch-icon" href="/apple-touch-icon.png"/>
+
+    <script id="mainscript" src="/script/main22.mjs" type="module"></script>
+</head>
+
+<body>
+<header>
+    <div class="gradient"></div>
+</header>
+
+<monster-state>
+    <img width="16" height="16" alt="tick" title="yes" src="data:image/gif;base64,R0lGODdhEAAQAMwAAPj7+FmhUYjNfGuxYYDJdYTIeanOpT+DOTuANXi/bGOrWj6CONzv2sPjv2Cm
+  V1unU4zPgI/Sg6DJnJ3ImTh8Mtbs00aNP1CZSGy0YqLEn47RgXW8amasW7XWsmmvX2iuXiwAAAAAEAAQAAAFVyAgjmRpnihqGCkpDQ
+  PbGkNUOFk6DZqgHCNGg2T4QAQBoIiRSAwBE4VA4FACKgkB5NGReASFZEmxsQ0whPDi9BiACYQAInXhwOUtgCUQoORFCGt/g4QAIQA7">
+    <h1 class="deco">Bad xxxx</h1>
+    <p>The request was incorrect, the server could not process it.
+    </p><p>
+</p><div class="infobox">
+    <div>
+
+        <ul>
+
+            <li>Try submitting your <a href="/a.html" title="Yes">request</a> again (sometimes this helps).</li>
+            <li>Contact support if you continue to have problems.</li>
+
+            <li>If you received this message as a result of a request to the server API, then check the structure
+                against the documentation.
+            </li>
+
+
+        </ul>
+
+        <p>You   can   try    the following steps:</p>
+        
+    </div>
+</div>
+
+
+</monster-state>
+
+
+
+</body></html>
\ No newline at end of file
diff --git a/development/examples/example1/original/test2.html b/development/examples/example1/original/test2.html
new file mode 100644
index 0000000000000000000000000000000000000000..3a4f24aa88a66a038aec5489009b3c393cae39fe
--- /dev/null
+++ b/development/examples/example1/original/test2.html
@@ -0,0 +1,71 @@
+<!DOCTYPE html><html lang="en"><head>
+
+    <style>
+        *:not(:defined) {
+            visibility: hidden;
+        }
+    </style>
+
+    <meta charset="utf-8"/>
+    <meta name="viewport" content="width=device-width, initial-scale=1"/>
+
+    <meta name="robots" content="noindex,noarchive"/>
+
+    <link rel="icon" type="image/x-icon" href="/asset/icon/favicon.svg"/>
+    <meta name="theme-color" content="#c10000"/>
+    <link rel="apple-touch-icon" sizes="180x180" href="/asset/icon/apple-touch-icon.png"/>
+    <link rel="icon" type="image/png" sizes="32x32" href="/asset/icon/favicon-32x32.png"/>
+    <link rel="icon" type="image/png" sizes="16x16" href="/asset/icon/favicon-16x16.png"/>
+    <link rel="mask-icon" href="/asset/icon/safari-pinned-tab.svg" color="#fd1d1d"/>
+    <meta name="msapplication-TileColor" content="#fd1d1d"/>
+    <meta name="msapplication-TileImage" content="/asset/icon/mstile-144x144.png"/>
+
+    <title>Bad Request ME</title>
+    <meta name="description" content="The request was malformed or invalid."/>
+    <meta name="author" content="schukai GmbH"/>
+
+    <link rel="icon" href="/favicon.ico"/>
+    <link rel="icon" href="/favicon.svg" type="image/svg+xml"/>
+    <link rel="apple-touch-icon" href="/apple-touch-icon.png"/>
+
+    <script id="mainscript" src="/script/main22.mjs" type="module"></script>
+</head>
+
+<body>
+<header>
+    <div class="gradient"></div>
+</header>
+
+<monster-state>
+    <img width="16" height="16" alt="tick" title="yes" src="data:image/gif;base64,R0lGODdhEAAQAMwAAPj7+FmhUYjNfGuxYYDJdYTIeanOpT+DOTuANXi/bGOrWj6CONzv2sPjv2Cm
+  V1unU4zPgI/Sg6DJnJ3ImTh8Mtbs00aNP1CZSGy0YqLEn47RgXW8amasW7XWsmmvX2iuXiwAAAAAEAAQAAAFVyAgjmRpnihqGCkpDQ
+  PbGkNUOFk6DZqgHCNGg2T4QAQBoIiRSAwBE4VA4FACKgkB5NGReASFZEmxsQ0whPDi9BiACYQAInXhwOUtgCUQoORFCGt/g4QAIQA7"/>
+    <h1 class="deco">Bad xxxx</h1>
+    <p>The request was incorrect, the server could not process it.
+    </p><p>
+</p><div class="infobox">
+    <div>
+
+        <ul>
+
+            <li>Try submitting your <a href="/a.html" title="Yes">request</a> again (sometimes this helps).</li>
+            <li>Contact support if you continue to have problems.</li>
+
+            <li>If you received this message as a result of a request to the server API, then check the structure
+                against the documentation.
+            </li>
+
+
+        </ul>
+
+        <p>You   can   try    the following steps:</p>
+        
+    </div>
+</div>
+
+
+</monster-state>
+
+
+
+</body></html>
\ No newline at end of file
diff --git a/development/examples/example1/original/test3.html b/development/examples/example1/original/test3.html
new file mode 100644
index 0000000000000000000000000000000000000000..3a4f24aa88a66a038aec5489009b3c393cae39fe
--- /dev/null
+++ b/development/examples/example1/original/test3.html
@@ -0,0 +1,71 @@
+<!DOCTYPE html><html lang="en"><head>
+
+    <style>
+        *:not(:defined) {
+            visibility: hidden;
+        }
+    </style>
+
+    <meta charset="utf-8"/>
+    <meta name="viewport" content="width=device-width, initial-scale=1"/>
+
+    <meta name="robots" content="noindex,noarchive"/>
+
+    <link rel="icon" type="image/x-icon" href="/asset/icon/favicon.svg"/>
+    <meta name="theme-color" content="#c10000"/>
+    <link rel="apple-touch-icon" sizes="180x180" href="/asset/icon/apple-touch-icon.png"/>
+    <link rel="icon" type="image/png" sizes="32x32" href="/asset/icon/favicon-32x32.png"/>
+    <link rel="icon" type="image/png" sizes="16x16" href="/asset/icon/favicon-16x16.png"/>
+    <link rel="mask-icon" href="/asset/icon/safari-pinned-tab.svg" color="#fd1d1d"/>
+    <meta name="msapplication-TileColor" content="#fd1d1d"/>
+    <meta name="msapplication-TileImage" content="/asset/icon/mstile-144x144.png"/>
+
+    <title>Bad Request ME</title>
+    <meta name="description" content="The request was malformed or invalid."/>
+    <meta name="author" content="schukai GmbH"/>
+
+    <link rel="icon" href="/favicon.ico"/>
+    <link rel="icon" href="/favicon.svg" type="image/svg+xml"/>
+    <link rel="apple-touch-icon" href="/apple-touch-icon.png"/>
+
+    <script id="mainscript" src="/script/main22.mjs" type="module"></script>
+</head>
+
+<body>
+<header>
+    <div class="gradient"></div>
+</header>
+
+<monster-state>
+    <img width="16" height="16" alt="tick" title="yes" src="data:image/gif;base64,R0lGODdhEAAQAMwAAPj7+FmhUYjNfGuxYYDJdYTIeanOpT+DOTuANXi/bGOrWj6CONzv2sPjv2Cm
+  V1unU4zPgI/Sg6DJnJ3ImTh8Mtbs00aNP1CZSGy0YqLEn47RgXW8amasW7XWsmmvX2iuXiwAAAAAEAAQAAAFVyAgjmRpnihqGCkpDQ
+  PbGkNUOFk6DZqgHCNGg2T4QAQBoIiRSAwBE4VA4FACKgkB5NGReASFZEmxsQ0whPDi9BiACYQAInXhwOUtgCUQoORFCGt/g4QAIQA7"/>
+    <h1 class="deco">Bad xxxx</h1>
+    <p>The request was incorrect, the server could not process it.
+    </p><p>
+</p><div class="infobox">
+    <div>
+
+        <ul>
+
+            <li>Try submitting your <a href="/a.html" title="Yes">request</a> again (sometimes this helps).</li>
+            <li>Contact support if you continue to have problems.</li>
+
+            <li>If you received this message as a result of a request to the server API, then check the structure
+                against the documentation.
+            </li>
+
+
+        </ul>
+
+        <p>You   can   try    the following steps:</p>
+        
+    </div>
+</div>
+
+
+</monster-state>
+
+
+
+</body></html>
\ No newline at end of file
diff --git a/development/examples/example1/snippets/meta/container.html b/development/examples/example1/snippets/meta/container.html
new file mode 100644
index 0000000000000000000000000000000000000000..2424762369803336a154c2d11af0f787e9c8df13
--- /dev/null
+++ b/development/examples/example1/snippets/meta/container.html
@@ -0,0 +1,27 @@
+<monster-state>
+    <img width="16" height="16" alt="tick" title="yes" src="data:image/gif;base64,R0lGODdhEAAQAMwAAPj7+FmhUYjNfGuxYYDJdYTIeanOpT+DOTuANXi/bGOrWj6CONzv2sPjv2Cm
+  V1unU4zPgI/Sg6DJnJ3ImTh8Mtbs00aNP1CZSGy0YqLEn47RgXW8amasW7XWsmmvX2iuXiwAAAAAEAAQAAAFVyAgjmRpnihqGCkpDQ
+  PbGkNUOFk6DZqgHCNGg2T4QAQBoIiRSAwBE4VA4FACKgkB5NGReASFZEmxsQ0whPDi9BiACYQAInXhwOUtgCUQoORFCGt/g4QAIQA7" id="tickyesdata-image-gi-4013311193" data-attributes="alt path:content.tickyesdata-image-gi-4013311193.alt,src path:content.tickyesdata-image-gi-4013311193.src,title path:content.tickyesdata-image-gi-4013311193.title"/>
+    <h1 class="deco"><span id="bad-request" data-replace-self="path:text.bad-request.text">Bad Request</span></h1>
+    <p><span id="the-request-was-inco-2640993422" data-replace-self="path:text.the-request-was-inco-2640993422.text">The request was incorrect, the server could not process it.
+    </span></p><p>
+</p><div class="infobox">
+    <div>
+
+        <ul>
+
+            <li data-state="monster">!!!!!!!!!!!!!!!!!!<a href="/a.html" title="Yes" id="yes-a-html" data-attributes="href path:anchors.yes-a-html.href,title path:anchors.yes-a-html.title,hreflang path:anchors.yes-a-html.hreflang">request</a> again (sometimes this helps).</li>
+            <li data-state="monster">!!!!!!!!!!!!!!!!!!</li>
+
+            <li data-state="monster">!!!!!!!!!!!!!!!!!!</li>
+
+
+        </ul>
+
+        <p><span id="you-can-try-the-foll-3363859033" data-replace-self="path:text.you-can-try-the-foll-3363859033.text">You   can   try    the following steps:</span></p>
+        
+    </div>
+</div>
+
+
+</monster-state>
\ No newline at end of file
diff --git a/development/examples/example1/template/data.yaml b/development/examples/example1/template/data.yaml
new file mode 100755
index 0000000000000000000000000000000000000000..518cba7fe81273a1271b3e56d00390de3e0b97f6
--- /dev/null
+++ b/development/examples/example1/template/data.yaml
@@ -0,0 +1,34 @@
+test.html:
+    lang: en
+    title: Bad Request
+    meta:
+        author: schukai GmbH
+        description: The request was malformed or invalid.
+    images:
+        - id: tickyesdata-image-gi-4013311193
+          source: |-
+            data:image/gif;base64,R0lGODdhEAAQAMwAAPj7+FmhUYjNfGuxYYDJdYTIeanOpT+DOTuANXi/bGOrWj6CONzv2sPjv2Cm
+              V1unU4zPgI/Sg6DJnJ3ImTh8Mtbs00aNP1CZSGy0YqLEn47RgXW8amasW7XWsmmvX2iuXiwAAAAAEAAQAAAFVyAgjmRpnihqGCkpDQ
+              PbGkNUOFk6DZqgHCNGg2T4QAQBoIiRSAwBE4VA4FACKgkB5NGReASFZEmxsQ0whPDi9BiACYQAInXhwOUtgCUQoORFCGt/g4QAIQA7
+          alt: tick
+          title: "yes"
+    anchors:
+        - id: yes-a-html
+          href: /b.html
+          hreflang: ""
+          title: "Yes"
+    text:
+        - text: Bad Request
+          id: bad-request
+        - text: The request was incorrect, the server could not process it.
+          id: the-request-was-inco-2640993422
+        - text: Try submitting your
+          id: try-submitting-your
+        - text: Contact support if you continue to have problems.
+          id: contact-support-if-y-3404332025
+        - text: |-
+            If you received this message as a result of a request to the server API, then check the structure
+                            against the documentation.
+          id: if-you-received-this-423958995
+        - text: 'You   can   try    the following steps:'
+          id: you-can-try-the-foll-3363859033
diff --git a/development/examples/example1/template/test.html b/development/examples/example1/template/test.html
new file mode 100644
index 0000000000000000000000000000000000000000..ab678048edbb1e41bb68cf5c18d65e7381b1378f
--- /dev/null
+++ b/development/examples/example1/template/test.html
@@ -0,0 +1,72 @@
+<!DOCTYPE html><html lang="en" data-attributes="lang path:lang"><head>
+
+    <style>
+        *:not(:defined) {
+            visibility: hidden;
+        }
+    </style>
+
+    <meta charset="utf-8"/>
+    <meta name="viewport" content="width=device-width, initial-scale=1"/>
+
+    <meta name="robots" content="noindex"/>
+
+    <link rel="icon" type="image/x-icon" href="/asset/icon/favicon.svg"/>
+    <meta name="theme-color" content="#c10000"/>
+    <link rel="apple-touch-icon" sizes="180x180" href="/asset/icon/apple-touch-icon.png"/>
+    <link rel="icon" type="image/png" sizes="32x32" href="/asset/icon/favicon-32x32.png"/>
+    <link rel="icon" type="image/png" sizes="16x16" href="/asset/icon/favicon-16x16.png"/>
+    <link rel="mask-icon" href="/asset/icon/safari-pinned-tab.svg" color="#fd1d1d"/>
+    <meta name="msapplication-TileColor" content="#fd1d1d"/>
+    <meta name="msapplication-TileImage" content="/asset/icon/mstile-144x144.png"/>
+
+    <title data-replace="path:title">Bad Request</title>
+    <meta name="description" content="The request was malformed or invalid." data-attributes="content path:meta.description"/>
+    <meta name="author" content="schukai GmbH" data-attributes="content path:meta.author"/>
+
+    <link rel="icon" href="/favicon.ico"/>
+    <link rel="icon" href="/favicon.svg" type="image/svg+xml"/>
+    <link rel="apple-touch-icon" href="/apple-touch-icon.png"/>
+
+    <script src="/script/main.mjs" type="module"></script>
+</head>
+
+<body>
+<header>
+    <div class="gradient"></div>
+</header>
+
+<monster-state>
+    <img width="16" height="16" alt="tick" title="yes" src="data:image/gif;base64,R0lGODdhEAAQAMwAAPj7+FmhUYjNfGuxYYDJdYTIeanOpT+DOTuANXi/bGOrWj6CONzv2sPjv2Cm
+  V1unU4zPgI/Sg6DJnJ3ImTh8Mtbs00aNP1CZSGy0YqLEn47RgXW8amasW7XWsmmvX2iuXiwAAAAAEAAQAAAFVyAgjmRpnihqGCkpDQ
+  PbGkNUOFk6DZqgHCNGg2T4QAQBoIiRSAwBE4VA4FACKgkB5NGReASFZEmxsQ0whPDi9BiACYQAInXhwOUtgCUQoORFCGt/g4QAIQA7" id="tickyesdata-image-gi-4013311193" data-attributes="alt path:content.tickyesdata-image-gi-4013311193.alt,src path:content.tickyesdata-image-gi-4013311193.src,title path:content.tickyesdata-image-gi-4013311193.title"/>
+    <h1 class="deco"><span id="bad-request" data-replace-self="path:text.bad-request.text">Bad Request</span></h1>
+    <p><span id="the-request-was-inco-2640993422" data-replace-self="path:text.the-request-was-inco-2640993422.text">The request was incorrect, the server could not process it.
+    </span></p><p>
+</p><div class="infobox">
+    <div>
+
+        <ul>
+
+            <li><span id="try-submitting-your" data-replace-self="path:text.try-submitting-your.text">Try submitting your </span><a href="/a.html" title="Yes" id="yes-a-html" 
+data-attributes="href path:anchors.yes-a-html.href,title path:anchors.yes-a-html.title,hreflang path:anchors.yes-a-html.hreflang">request</a> again (sometimes this helps).</li>
+            <li><span id="contact-support-if-y-3404332025" data-replace-self="path:text.contact-support-if-y-3404332025.text">Contact support if you continue to have problems.</span></li>
+
+            <li><span id="if-you-received-this-423958995" data-replace-self="path:text.if-you-received-this-423958995.text">If you received this message as a result of a request to the server API, then check the structure
+                against the documentation.
+            </span></li>
+
+
+        </ul>
+
+        <p><span id="you-can-try-the-foll-3363859033" data-replace-self="path:text.you-can-try-the-foll-3363859033.text">You   can   try    the following steps:</span></p>
+        
+    </div>
+</div>
+
+
+</monster-state>
+
+
+
+</body></html>
\ No newline at end of file