als-layout 2.1.0 → 2.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,8 @@
1
+ const { readFileSync, writeFileSync, readdirSync } = require('fs')
2
+ const { join } = require('path')
3
+
4
+ const docsDir = join(__dirname, 'docs')
5
+ const files = readdirSync(docsDir)
6
+ const content = files.map(file => readFileSync(join(docsDir, file), 'utf-8')).join('\n');
7
+ writeFileSync(join(__dirname, 'readme.md'), content, 'utf-8')
8
+
package/docs/#.md ADDED
@@ -0,0 +1,27 @@
1
+ # als-layout Documentation
2
+
3
+ ## Library Description
4
+
5
+ ### What is it?
6
+ `als-layout` is a JavaScript library designed to simplify and enhance the process of constructing and managing web page layouts. It provides a comprehensive API for modifying HTML documents dynamically, allowing developers to add, update, and manipulate various elements such as meta tags, styles, scripts, and more.
7
+
8
+ ### Why is it needed?
9
+ Managing HTML document structures and their contents can often become repetitive and error-prone when done manually. `als-modular` offers a structured and reusable approach, reducing development time and improving code maintainability.
10
+
11
+ ### What can you do with it and where can it be used?
12
+ The `als-layout` library is versatile, suitable for:
13
+ - Building dynamic web pages that require frequent updates to their metadata, styles, or scripts.
14
+ - Creating templating systems where multiple page layouts share similar structures but differ in content or styling.
15
+ - Developing web applications that need to dynamically adjust their UI based on user interactions or data changes.
16
+ This library is particularly useful in environments where rapid development and modular design are prioritized.
17
+
18
+ ## Installation and Adding
19
+ To use the `als-layout` library in your project, you can install it via npm and then include it in your JavaScript files:
20
+
21
+ ```bash
22
+ npm i als-layout
23
+ ```
24
+
25
+ ```js
26
+ const Layout = require('als-layout')
27
+ ```
@@ -0,0 +1,16 @@
1
+ ## Change Log
2
+ * V2.2.0
3
+ * fixed empty update function if no components for $App
4
+ * if component function return string, it will element.innerHTML = string
5
+ * Now each Layout extends Document (als-document)
6
+ * layout.$ and layout.$$
7
+ * Also $App.$ and $App.$$ on backend too
8
+ * no langs validation any more
9
+ * lang method instead
10
+ * no layout.cached
11
+ * charset meta tag allready exists by default
12
+ * V2.1.0
13
+ * updated als-document version
14
+ * [part] attribute for static components
15
+ * onload() method
16
+ * bugs fixed
@@ -0,0 +1,49 @@
1
+ ## Basic Usage
2
+
3
+ ### Initialization
4
+ To start using `als-layout`, you first need to create a new instance of `Layout`. This instance will serve as the foundation for building and modifying your web page.
5
+
6
+ ```js
7
+ const Layout = require('als-layout');
8
+ const layout = new Layout();
9
+ ```
10
+
11
+ ### Adding Different Elements
12
+ Once you have your `Layout` instance, you can easily add or modify various elements of your web page. Here are some examples of how you can use the library to customize your layout:
13
+
14
+ ```js
15
+ const layout = new Layout()
16
+ .charset() // default UTF-8
17
+ .viewport() // default width=device-width, initial-scale=1.0
18
+ .title('Test title') // adding/updating title and meta[og:title]
19
+ .favicon('/favicon.png') // adding/updating link[rel=icon][type=image/x-icon] with new href
20
+ .keywords(['some', 'keyword']) // adding/updating meta[name=keywords]. not adding existing keywords
21
+ .image('/main-image.png', '1.5') // adding/updating meta - og:image, twitter:image, twitter:card
22
+ .description('Cool site') // adding/updating meta og:description, twitter:description, and description tag
23
+ .version('1.0.0') // adds version parameter to link, script.src, and image
24
+ .url('/some', 'http://site.com') // adding/updating meta[og:url] and link[rel="canonical"]
25
+ .style([{body:{m:0, bgc:'whitesmoke'}}]) // adding as simple-css styles to existing/new style tag
26
+ .style('body {margin:0; background-color:whitesmoke;}', true) // adding css styles to existing/new style tag. Second parameter is minified (default=false).
27
+ .link('/styles.css', '2.0') // adding link[rel=stylesheet] if such href not exists
28
+ .script({src:'/app.js'}, '', true, '3.0') // set script with src to head if such src not exists
29
+ .script({}, 'console.log("hello world")', false) // set script with script code to footer
30
+
31
+ // Accessors for document parts
32
+ layout.body // getter for body element (if not exists, created)
33
+ layout.head // getter for head element (if not exists, created)
34
+ layout.html // getter for html Element (if not exists, created)
35
+
36
+ // Outputs
37
+ layout.rawHtml // raw HTML of the document
38
+ layout.clone // creates a new layout object clone for current object
39
+ ```
40
+
41
+ ### onload
42
+
43
+ By adding onload attribute, you can run scripts for each element after dom content has loaded.
44
+
45
+ Example how it works:
46
+ ```js
47
+ const layout = new Layout().charset().viewport().title('On load').onload()
48
+ layout.body.innerHTML = /*html*/`<div onload="this.innerHTML = 'new content'">original content</div>`
49
+ ```
@@ -0,0 +1,19 @@
1
+ ## Cloning Functionality
2
+
3
+ ### What is Cloning and Why is it Necessary?
4
+ Cloning in the `als-layout` library refers to creating a complete, independent copy of the existing `Layout` instance. This functionality is crucial when you need to generate multiple pages or versions of a page from a single base layout without affecting the original setup.
5
+
6
+ ### How to Use Cloning
7
+ To clone a `Layout` instance, simply use the `clone` method. This method creates a new `Layout` instance with the same properties and settings as the original, allowing for independent modifications without interference.
8
+
9
+ ```js
10
+ const newLayout = layout.clone;
11
+ ```
12
+
13
+ ### Benefits of Cloning
14
+ - **Efficiency:** Cloning is highly efficient, especially for creating pages with similar structures but different content or styles. It avoids the overhead of reinitializing and reconfiguring a new `Layout` instance from scratch.
15
+ - **Speed:** Cloning is fast, typically taking less than 20ms even for large pages. This makes it ideal for high-performance web applications that need to dynamically generate content.
16
+ - **Isolation:** Changes made to a cloned `Layout` do not affect the original, ensuring that each instance can be modified independently based on specific requirements.
17
+
18
+ Cloning is particularly useful in scenarios where templates or base layouts are used repeatedly with slight variations, providing a robust and scalable solution for web page generation.
19
+
@@ -0,0 +1,43 @@
1
+ ## Advanced Usage
2
+
3
+ The `als-layout` library allows for sophisticated manipulation of web page layouts, providing robust tools for creating dynamic and complex web pages. Below is an advanced example demonstrating various capabilities of the library:
4
+
5
+ ```js
6
+ const Layout = require('als-layout')
7
+
8
+ // Starting with a basic HTML template and specifying the host for URL methods
9
+ const raw = /*html*/`<html></html>`
10
+ const host = 'http://example.com';
11
+ const layout = new Layout(raw, host).lang('fr')
12
+ console.log(layout.rawHtml)
13
+ // <!DOCTYPE html><html lang="fr"><head></p></head><body></body></html>
14
+
15
+ // Cloning the initial layout to create a specialized page
16
+ const homePage = layout.clone
17
+ homeAutoReload = layout.clone
18
+ homePage.title('Home page')
19
+ homePage.body.innerHTML = /*html*/`<h1>Home page</h1>`
20
+ console.log(homePage.rawHtml)
21
+ // <!DOCTYPE html><html lang="fr"><head><title>Home page</title><meta property="og:title" content="Home page"></head><body><h1>Home page</h1></body></html>
22
+
23
+ // Adding script that reloads the page every minute
24
+ homeAutoReload.script({}, 'setTimeout(function() { window.location.reload(); }, 60000);', false)
25
+ console.log(homeAutoReload.rawHtml)
26
+ // <!DOCTYPE html><html lang="fr"><head><title>Automatic Reload Page</title><meta property="og:title" content="Automatic Reload Page"></head><body><script>setTimeout(function() { window.location.reload(); }, 60000);</script></body></html>
27
+
28
+ // Demonstrating dynamic stylesheet linkage with versioning
29
+ const styleVersion = '1.1';
30
+ homePage.link('/css/main.css', styleVersion)
31
+ console.log(homePage.rawHtml)
32
+ // Includes link to the stylesheet with version parameter to ensure fresh cache
33
+ ```
34
+
35
+ In this example:
36
+ - We start with a basic HTML template and use the `lang` method to set the language.
37
+ - We use the `clone` method to create two versions of the base layout: one for the home page and another that automatically reloads every minute.
38
+ - We manipulate the `body` of the `homePage` to include custom HTML.
39
+ - We add a script to `homeAutoReload` that sets up an automatic page reload, showcasing how to insert JavaScript dynamically.
40
+ - We dynamically add a versioned link to a stylesheet in the `homePage`, demonstrating control over caching and resource management.
41
+
42
+ This advanced example illustrates how `als-layout` can be used to handle complex scenarios and requirements in web development, enhancing the flexibility and power at your disposal.
43
+
@@ -0,0 +1,71 @@
1
+ ## Rendering
2
+
3
+ Each instance of `Layout` comes equipped with a `render` method that compiles the HTML structure and embeds a JavaScript object to manage the page dynamically. This object, known as `window.$App`, allows for real-time interaction and updates within the page.
4
+
5
+ ### Structure
6
+ The layout object houses several key properties that facilitate dynamic content management:
7
+
8
+ - `layout.data`: Stores the data that can be used across the page, such as state variables or configuration settings.
9
+ - `layout.components`: Holds functions that define the behavior and rendering logic for components identified by specific attributes in the HTML.
10
+ - `layout.utils`: Contains utility functions that can be used throughout the page for common tasks.
11
+ - `layout.actions`: Methods that can be triggered by user interaction, often modifying `layout.data` and updating the page accordingly.
12
+
13
+ ### The Render Method
14
+ The `render` method processes all elements with a `component` attribute, dynamically generating their content and behavior based on the defined components. After rendering, the page includes the `window.$App` JavaScript object, which provides methods and properties to interact with the page elements and data:
15
+
16
+ ```js
17
+ window.$App = {
18
+ data, // Access to the layout data object
19
+ components, // Access to components functions
20
+ utils, // Access to utility functions
21
+ actions, // Access to action functions
22
+ $(selector, parent = document), // Equivalent to querySelector
23
+ $$(selector, parent = document), // Equivalent to querySelectorAll
24
+ update(element) { // Updates the element if it has a component attribute
25
+ // Update logic here
26
+ }
27
+ }
28
+ ```
29
+
30
+ ### Counter Example
31
+ To demonstrate dynamic interaction, consider a counter that can be increased or decreased through user input:
32
+
33
+ ```js
34
+ const fs = require('fs')
35
+ const Layout = require('als-layout')
36
+
37
+ // Create and configure the layout
38
+ const layout = new Layout().title('Counter')
39
+ layout.data.counter = 0 // Initialize counter data
40
+
41
+ // Define a component for displaying the counter
42
+ layout.components.counter = function(element, $App) {
43
+ element.innerHTML = `${$App.data.counter}`
44
+ }
45
+
46
+ // Define actions for increasing and decreasing the counter
47
+ layout.actions = {
48
+ increase: () => { $App.data.counter++; $App.update($App.$('[component=counter]')); },
49
+ decrease: () => { $We render the html page to measure and write to a document.app.data.counter--; $Page updates are shown in real-time on the rendered HTML.$App.update($App.$('[component=counter]')); }
50
+ }
51
+
52
+ // Add buttons and the counter display to the body
53
+ layout.body.innerHTML = /*html*/`
54
+ <button onclick="$App.actions.increase()">Increase</button>
55
+ <span component="counter"></span>
56
+ <button onclick="$App.actions.decrease()">Decrease</button>
57
+ `
58
+
59
+ // Measure render time and generate HTML
60
+ const time1 = performance.now()
61
+ const rawHtml = layout.render()
62
+ const time2 = performance.now()
63
+ console.log(`${time2 - time1}ms`) // e.g., 1.0649ms
64
+
65
+ // Write the output to a file
66
+ fs.writeFileSync('counter.html', rawHtml, 'utf-8')
67
+ ```
68
+
69
+ ### Advanced Rendering Details
70
+ - **Component Indexing:** Each component is assigned a `componentIndex` during rendering, providing a unique index within its parent component.
71
+ - **Part Attribute:** Using the `part` attribute in a component prevents it from being added to `$App.components`, unless it is nested within another component.
package/lib/layout.js CHANGED
@@ -1,81 +1,44 @@
1
- const { cacheDoc } = require('als-document')
2
- const {
3
- addKeywords, addStyle, addDescription, addTitle, addImage,
4
- addUrl, addFavicon, addScript, addLink, charset, viewport
5
- } = require('./elements/index')
1
+ const { Document } = require('als-document')
6
2
  const build$App = require('./render/build-app')
7
- const buildRoot = require('./build-root')
8
3
  const onload = require('./onload')
9
- class Layout {
10
- constructor(layout, options = {}) {
11
- this.options = options
12
- this.root = buildRoot(layout)
13
- this.body; this.head;
4
+ const update = require('./render/update')
5
+ const {
6
+ addKeywords, addStyle, addDescription, addTitle, addImage,
7
+ addUrl, addFavicon, addScript,addLink,charset,viewport
8
+ } = require('./elements/index')
9
+
10
+ class Layout extends Document {
11
+ constructor(html,url) {
12
+ super(html,url)
14
13
  this.components = {}
15
14
  this.data = {}
16
15
  this.actions = {}
17
16
  this.utils = {}
17
+ this.root = this.html
18
+ this.update = update
18
19
  }
19
-
20
20
  onload() {this.script({},onload); return this}
21
-
22
- get html() {
23
- const lang = this.options.lang || 'en'
24
- if (!this.root.$('html')) this.root.insert(2, `<html></html>`)
25
- const htmlElement = this.root.$('html')
26
- if (lang && htmlElement.getAttribute('lang') !== lang) {
27
- htmlElement.setAttribute('lang', lang)
28
- }
29
- return htmlElement
30
- }
31
- get body() {
32
- if (!this.root.$('body')) this.html.insert(2, `<body></body>`)
33
- return this.root.$('body')
34
- }
35
- get head() {
36
- if (!this.root.$('head')) this.html.insert(1, `<head></head>`)
37
- return this.root.$('head')
38
- }
39
-
40
- update(element, done = []) {
41
- for (const componentName in this.components) {
42
- const fn = this.components[componentName]
43
- let components = element.getAttribute('component') === componentName
44
- ? [element]
45
- : [...element.querySelectorAll(`[component=${componentName}]`)]
46
- components = components.filter(el => !done.includes(el))
47
- components.forEach((element, i) => {
48
- element.componentIndex = i
49
- fn(element, this)
50
- done.push(element)
51
- this.update(element, done)
52
- });
53
- }
54
- }
55
-
56
- render() {
57
- const done = []
58
- this.update(this.root, done)
59
- this.script({}, build$App(done,this),false)
60
- return this.rawHtml
61
- }
62
-
63
- get rawHtml() { return this.root.innerHTML }
64
- get cached() { return cacheDoc(this.root) }
65
- get clone() { return new Layout(this.root, this.options) }
66
-
21
+ lang(lang) {this.html.setAttribute('lang',lang); return this}
67
22
  version(v) { this.v = v; return this; }
23
+ charset(newCharset = 'UTF-8') { return charset(newCharset, this) }
68
24
  keywords(keywords = []) { return addKeywords(keywords, this) }
69
25
  description(description) { return addDescription(description, this) }
70
26
  title(title) { return addTitle(title, this) }
71
27
  style(styles, minified) { return addStyle(styles, minified, this) }
72
28
  image(image, v = this.v) { return addImage(image, v, this) }
73
- url(url, host = this.options.host) { return addUrl(url, host, this) }
29
+ url(url, host = this.URL) { return addUrl(url, host, this) }
74
30
  favicon(href) { return addFavicon(href, this) }
75
31
  script(attributes, innerHTML, head = true, v = this.v) { return addScript(attributes, innerHTML, head, v, this) }
76
32
  link(href, v = this.v) { return addLink(href, v, this) }
77
- charset(newCharset = 'UTF-8') { return charset(newCharset, this) }
78
33
  viewport(newViewport = 'width=device-width, initial-scale=1.0') { return viewport(newViewport, this) }
34
+ get rawHtml() {return this.innerHTML}
35
+ get clone() {return new Layout(new Document(this),this.URL)}
36
+ render() {
37
+ const done = []
38
+ this.update(this.root, done)
39
+ this.script({}, build$App(done,this),false)
40
+ return this.rawHtml
41
+ }
79
42
  }
80
43
 
81
44
  module.exports = Layout
@@ -1,11 +1,12 @@
1
1
  const componentHierarchy = require('./component-hierarchy')
2
2
  module.exports = function(done=[],layout) {
3
3
  let strComponents = 'components:{}', updateFn = 'update:()=>{}'
4
- if(done.length) {
5
- strComponents = 'components:{'+componentHierarchy(done).map(componentName => {
4
+ const components = componentHierarchy(done)
5
+ if(components.length) {
6
+ strComponents = 'components:{'+components.map(componentName => {
6
7
  return `"${componentName}":${layout.components[componentName].toString()}`
7
8
  }).join(',')+'}'
8
- updateFn = `update:function ${layout.update.toString()}`
9
+ updateFn = `update:${layout.update.toString()}`
9
10
  }
10
11
  const strData = 'data:'+JSON.stringify(layout.data)
11
12
  const $ = 'function $(selector,parent = document) {return parent.querySelector(selector)}'
@@ -0,0 +1,19 @@
1
+ function update(element, done = []) {
2
+ for (const componentName in this.components) {
3
+ const fn = this.components[componentName]
4
+ let components = element.getAttribute('component') === componentName
5
+ ? [element]
6
+ : [...element.querySelectorAll(`[component=${componentName}]`)]
7
+ components = components.filter(el => !done.includes(el))
8
+ components.forEach((element, i) => {
9
+ element.componentIndex = i
10
+ const result = fn(element, this)
11
+ if(typeof result === 'string') element.innerHTML = result
12
+ done.push(element)
13
+ this.update(element, done)
14
+ });
15
+ }
16
+ }
17
+
18
+
19
+ module.exports = update
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "als-layout",
3
- "version": "2.1.0",
3
+ "version": "2.2.0",
4
4
  "description": "Html layout constructor",
5
5
  "main": "index.js",
6
6
  "directories": {
@@ -15,7 +15,7 @@
15
15
  "license": "ISC",
16
16
  "dependencies": {
17
17
  "als-css-parser": "^0.5.0",
18
- "als-document": "^1.2.1",
18
+ "als-document": "^1.3.1",
19
19
  "als-simple-css": "^9.1.0"
20
20
  }
21
21
  }
package/readme.md CHANGED
@@ -1,24 +1,61 @@
1
- # Als-layout
1
+ # als-layout Documentation
2
2
 
3
- `Als-layout` is an HTML layout constructor for Node.js that allows you to manage HTML elements, styles, and scripts through JavaScript. It's perfect for server-side HTML generation or dynamic page modifications before delivery to the client.
3
+ ## Library Description
4
4
 
5
- ## What's New in 2.1.0
5
+ ### What is it?
6
+ `als-layout` is a JavaScript library designed to simplify and enhance the process of constructing and managing web page layouts. It provides a comprehensive API for modifying HTML documents dynamically, allowing developers to add, update, and manipulate various elements such as meta tags, styles, scripts, and more.
6
7
 
7
- * updated als-document version
8
- * [part] attribute for static components
9
- * onload() method
10
- * bugs fixed
8
+ ### Why is it needed?
9
+ Managing HTML document structures and their contents can often become repetitive and error-prone when done manually. `als-modular` offers a structured and reusable approach, reducing development time and improving code maintainability.
11
10
 
12
- ## Install
11
+ ### What can you do with it and where can it be used?
12
+ The `als-layout` library is versatile, suitable for:
13
+ - Building dynamic web pages that require frequent updates to their metadata, styles, or scripts.
14
+ - Creating templating systems where multiple page layouts share similar structures but differ in content or styling.
15
+ - Developing web applications that need to dynamically adjust their UI based on user interactions or data changes.
16
+ This library is particularly useful in environments where rapid development and modular design are prioritized.
17
+
18
+ ## Installation and Adding
19
+ To use the `als-layout` library in your project, you can install it via npm and then include it in your JavaScript files:
13
20
 
14
21
  ```bash
15
22
  npm i als-layout
16
23
  ```
17
24
 
25
+ ```js
26
+ const Layout = require('als-layout')
27
+ ```
28
+
29
+ ## Change Log
30
+ * V2.2.0
31
+ * fixed empty update function if no components for $App
32
+ * if component function return string, it will element.innerHTML = string
33
+ * Now each Layout extends Document (als-document)
34
+ * layout.$ and layout.$$
35
+ * Also $App.$ and $App.$$ on backend too
36
+ * no langs validation any more
37
+ * lang method instead
38
+ * no layout.cached
39
+ * charset meta tag allready exists by default
40
+ * V2.1.0
41
+ * updated als-document version
42
+ * [part] attribute for static components
43
+ * onload() method
44
+ * bugs fixed
18
45
  ## Basic Usage
19
46
 
47
+ ### Initialization
48
+ To start using `als-layout`, you first need to create a new instance of `Layout`. This instance will serve as the foundation for building and modifying your web page.
49
+
50
+ ```js
51
+ const Layout = require('als-layout');
52
+ const layout = new Layout();
53
+ ```
54
+
55
+ ### Adding Different Elements
56
+ Once you have your `Layout` instance, you can easily add or modify various elements of your web page. Here are some examples of how you can use the library to customize your layout:
57
+
20
58
  ```js
21
- const Layout = require('als-layout')
22
59
  const layout = new Layout()
23
60
  .charset() // default UTF-8
24
61
  .viewport() // default width=device-width, initial-scale=1.0
@@ -38,108 +75,154 @@ const layout = new Layout()
38
75
  // Accessors for document parts
39
76
  layout.body // getter for body element (if not exists, created)
40
77
  layout.head // getter for head element (if not exists, created)
41
- layout.html // getter for html element (if not exists, created)
78
+ layout.html // getter for html Element (if not exists, created)
42
79
 
43
80
  // Outputs
44
- layout.rawHtml // raw html
45
- layout.cached // cached DOM
46
- layout.clone // new layout object clone for current object
81
+ layout.rawHtml // raw HTML of the document
82
+ layout.clone // creates a new layout object clone for current object
47
83
  ```
48
84
 
85
+ ### onload
86
+
87
+ By adding onload attribute, you can run scripts for each element after dom content has loaded.
88
+
89
+ Example how it works:
90
+ ```js
91
+ const layout = new Layout().charset().viewport().title('On load').onload()
92
+ layout.body.innerHTML = /*html*/`<div onload="this.innerHTML = 'new content'">original content</div>`
93
+ ```
94
+ ## Cloning Functionality
95
+
96
+ ### What is Cloning and Why is it Necessary?
97
+ Cloning in the `als-layout` library refers to creating a complete, independent copy of the existing `Layout` instance. This functionality is crucial when you need to generate multiple pages or versions of a page from a single base layout without affecting the original setup.
98
+
99
+ ### How to Use Cloning
100
+ To clone a `Layout` instance, simply use the `clone` method. This method creates a new `Layout` instance with the same properties and settings as the original, allowing for independent modifications without interference.
101
+
102
+ ```js
103
+ const newLayout = layout.clone;
104
+ ```
105
+
106
+ ### Benefits of Cloning
107
+ - **Efficiency:** Cloning is highly efficient, especially for creating pages with similar structures but different content or styles. It avoids the overhead of reinitializing and reconfiguring a new `Layout` instance from scratch.
108
+ - **Speed:** Cloning is fast, typically taking less than 20ms even for large pages. This makes it ideal for high-performance web applications that need to dynamically generate content.
109
+ - **Isolation:** Changes made to a cloned `Layout` do not affect the original, ensuring that each instance can be modified independently based on specific requirements.
110
+
111
+ Cloning is particularly useful in scenarios where templates or base layouts are used repeatedly with slight variations, providing a robust and scalable solution for web page generation.
112
+
113
+
49
114
  ## Advanced Usage
50
115
 
116
+ The `als-layout` library allows for sophisticated manipulation of web page layouts, providing robust tools for creating dynamic and complex web pages. Below is an advanced example demonstrating various capabilities of the library:
117
+
51
118
  ```js
52
- const Layout = require('./lib/layout')
119
+ const Layout = require('als-layout')
53
120
 
121
+ // Starting with a basic HTML template and specifying the host for URL methods
54
122
  const raw = /*html*/`<html></html>`
55
- const options = {
56
- host:'http://example.com', // host for url method
57
- lang:'fr' // for <html lang="fr"></html>
58
- }
59
- const layout = new Layout(raw, options)
123
+ const host = 'http://example.com';
124
+ const layout = new Layout(raw, host).lang('fr')
60
125
  console.log(layout.rawHtml)
61
- // <!DOCTYPE html><html lang="fr"><head></head><body></body></html>
126
+ // <!DOCTYPE html><html lang="fr"><head></p></head><body></body></html>
62
127
 
128
+ // Cloning the initial layout to create a specialized page
63
129
  const homePage = layout.clone
130
+ homeAutoReload = layout.clone
64
131
  homePage.title('Home page')
65
132
  homePage.body.innerHTML = /*html*/`<h1>Home page</h1>`
66
133
  console.log(homePage.rawHtml)
67
134
  // <!DOCTYPE html><html lang="fr"><head><title>Home page</title><meta property="og:title" content="Home page"></head><body><h1>Home page</h1></body></html>
135
+
136
+ // Adding script that reloads the page every minute
137
+ homeAutoReload.script({}, 'setTimeout(function() { window.location.reload(); }, 60000);', false)
138
+ console.log(homeAutoReload.rawHtml)
139
+ // <!DOCTYPE html><html lang="fr"><head><title>Automatic Reload Page</title><meta property="og:title" content="Automatic Reload Page"></head><body><script>setTimeout(function() { window.location.reload(); }, 60000);</script></body></html>
140
+
141
+ // Demonstrating dynamic stylesheet linkage with versioning
142
+ const styleVersion = '1.1';
143
+ homePage.link('/css/main.css', styleVersion)
144
+ console.log(homePage.rawHtml)
145
+ // Includes link to the stylesheet with version parameter to ensure fresh cache
68
146
  ```
69
147
 
148
+ In this example:
149
+ - We start with a basic HTML template and use the `lang` method to set the language.
150
+ - We use the `clone` method to create two versions of the base layout: one for the home page and another that automatically reloads every minute.
151
+ - We manipulate the `body` of the `homePage` to include custom HTML.
152
+ - We add a script to `homeAutoReload` that sets up an automatic page reload, showcasing how to insert JavaScript dynamically.
153
+ - We dynamically add a versioned link to a stylesheet in the `homePage`, demonstrating control over caching and resource management.
154
+
155
+ This advanced example illustrates how `als-layout` can be used to handle complex scenarios and requirements in web development, enhancing the flexibility and power at your disposal.
156
+
157
+
70
158
  ## Rendering
71
159
 
72
- Each layout instance has a render method and the following objects:
73
- ```js
74
- layout.data
75
- layout.components
76
- layout.utils
77
- layout.actions
78
- ```
160
+ Each instance of `Layout` comes equipped with a `render` method that compiles the HTML structure and embeds a JavaScript object to manage the page dynamically. This object, known as `window.$App`, allows for real-time interaction and updates within the page.
161
+
162
+ ### Structure
163
+ The layout object houses several key properties that facilitate dynamic content management:
79
164
 
80
- The render method returns raw HTML after building elements with the attribute component. It will create HTML raw which will include a `window.$App` object with the following:
165
+ - `layout.data`: Stores the data that can be used across the page, such as state variables or configuration settings.
166
+ - `layout.components`: Holds functions that define the behavior and rendering logic for components identified by specific attributes in the HTML.
167
+ - `layout.utils`: Contains utility functions that can be used throughout the page for common tasks.
168
+ - `layout.actions`: Methods that can be triggered by user interaction, often modifying `layout.data` and updating the page accordingly.
169
+
170
+ ### The Render Method
171
+ The `render` method processes all elements with a `component` attribute, dynamically generating their content and behavior based on the defined components. After rendering, the page includes the `window.$App` JavaScript object, which provides methods and properties to interact with the page elements and data:
81
172
 
82
173
  ```js
83
174
  window.$App = {
84
- data,
85
- components,
86
- utils,
87
- actions,
88
- $(selector, parent=document), // querySelector
89
- $$(selector, parent=document), // querySelectorAll
90
- update(element), // update element if it has component attribute
175
+ data, // Access to the layout data object
176
+ components, // Access to components functions
177
+ utils, // Access to utility functions
178
+ actions, // Access to action functions
179
+ $(selector, parent = document), // Equivalent to querySelector
180
+ $$(selector, parent = document), // Equivalent to querySelectorAll
181
+ update(element) { // Updates the element if it has a component attribute
182
+ // Update logic here
183
+ }
91
184
  }
92
185
  ```
93
186
 
94
-
95
- ## Counter Example
187
+ ### Counter Example
188
+ To demonstrate dynamic interaction, consider a counter that can be increased or decreased through user input:
96
189
 
97
190
  ```js
98
191
  const fs = require('fs')
99
192
  const Layout = require('als-layout')
100
193
 
101
- const layout = new Layout().charset().viewport().title('Counter')
102
- layout.data.counter = 0
194
+ // Create and configure the layout
195
+ const layout = new Layout().title('Counter')
196
+ layout.data.counter = 0 // Initialize counter data
197
+
198
+ // Define a component for displaying the counter
103
199
  layout.components.counter = function(element, $App) {
104
200
  element.innerHTML = `${$App.data.counter}`
105
201
  }
106
202
 
203
+ // Define actions for increasing and decreasing the counter
107
204
  layout.actions = {
108
- increase: () => { $App.data.counter++; $App.update($App.$('[component=counter]')) },
109
- decrease: () => { $App.data.counter--; $App.update($App.$('[component=counter]')) }
205
+ increase: () => { $App.data.counter++; $App.update($App.$('[component=counter]')); },
206
+ decrease: () => { $We render the html page to measure and write to a document.app.data.counter--; $Page updates are shown in real-time on the rendered HTML.$App.update($App.$('[component=counter]')); }
110
207
  }
111
208
 
209
+ // Add buttons and the counter display to the body
112
210
  layout.body.innerHTML = /*html*/`
113
211
  <button onclick="$App.actions.increase()">Increase</button>
114
212
  <span component="counter"></span>
115
213
  <button onclick="$App.actions.decrease()">Decrease</button>
116
214
  `
215
+
216
+ // Measure render time and generate HTML
117
217
  const time1 = performance.now()
118
218
  const rawHtml = layout.render()
119
219
  const time2 = performance.now()
120
220
  console.log(`${time2 - time1}ms`) // e.g., 1.0649ms
121
221
 
222
+ // Write the output to a file
122
223
  fs.writeFileSync('counter.html', rawHtml, 'utf-8')
123
224
  ```
124
225
 
125
- Each component gets a `componentIndex` which is available inside the component function.
126
- ```js
127
- element.componentIndex
128
- ```
129
-
130
-
131
- ### parts
132
-
133
- By default render method adds all used components to `$App.components`.
134
- By adding `part` attribute component will not be added, except cases, the component is part of another component.
135
-
136
-
137
- ## onload
138
-
139
- By adding onload attribute, you can run scripts for each element after dom content has loaded.
140
-
141
- Example how it works:
142
- ```js
143
- const layout = new Layout().charset().viewport().title('On load').onload()
144
- layout.body.innerHTML = /*html*/`<div onload="this.innerHTML = 'new content'">original content</div>`
145
- ```
226
+ ### Advanced Rendering Details
227
+ - **Component Indexing:** Each component is assigned a `componentIndex` during rendering, providing a unique index within its parent component.
228
+ - **Part Attribute:** Using the `part` attribute in a component prevents it from being added to `$App.components`, unless it is nested within another component.
@@ -17,7 +17,8 @@ describe('Layout Initialization', () => {
17
17
  it('should allow setting a custom language', () => {
18
18
  const customLang = 'fr';
19
19
  const layout = new Layout(undefined, { lang: customLang });
20
- assert(layout.options.lang === customLang, `language is not set to ${customLang}`);
20
+ layout.lang(customLang)
21
+ assert(layout.html.getAttribute('lang') === customLang, `language is not set to ${customLang}`);
21
22
  });
22
23
 
23
24
  it('should initialize development mode as undefined or false', () => {
@@ -32,16 +33,8 @@ describe('Layout Initialization', () => {
32
33
 
33
34
  it('should allow setting a custom host', () => {
34
35
  const customHost = 'http://localhost';
35
- const layout = new Layout(undefined, { host: customHost });
36
- assert.strictEqual(layout.options.host, customHost, `host is not set to ${customHost}`);
36
+ const layout = new Layout(undefined,customHost);
37
+ console.log(layout.URL)
38
+ assert.strictEqual(layout.URL, customHost, `host is not set to ${customHost}`);
37
39
  });
38
-
39
- it('check method',() => {
40
- const cached = cacheDoc(new Root())
41
- const layout = new Layout(cached)
42
- const root = layout.root
43
- assert(root.$('html') !== null)
44
- assert(root.$('head') !== null)
45
- assert(root.$('body') !== null)
46
- })
47
40
  });
@@ -20,7 +20,7 @@ describe('Charset tests', () => {
20
20
  it('should insert charset at second position if not present', () => {
21
21
  const charset = 'UTF-8';
22
22
  layout.charset(charset);
23
- assert.strictEqual(layout.head.childNodes[0].tagName, 'meta', 'Meta should be at second position');
23
+ assert.strictEqual(layout.head.childNodes[0].tagName, 'META', 'Meta should be at second position');
24
24
  assert.strictEqual(layout.head.childNodes[0].getAttribute('charset'), charset, 'Charset not set correctly');
25
25
  });
26
26
 
@@ -50,7 +50,7 @@ describe('Favicon tests', () => {
50
50
  it('should insert favicon at second position if not present', () => {
51
51
  const faviconHref = 'favicon.ico';
52
52
  layout.favicon(faviconHref);
53
- assert.strictEqual(layout.head.childNodes[0].tagName, 'link', 'Favicon link should be at second position');
53
+ assert.strictEqual(layout.head.childNodes[0].tagName, 'LINK', 'Favicon link should be at second position');
54
54
  assert.strictEqual(layout.head.childNodes[0].getAttribute('href'), faviconHref, 'Favicon href not set correctly');
55
55
  });
56
56
 
@@ -265,7 +265,7 @@ describe('Scripts', () => {
265
265
  it('should add script after body when head is false', () => {
266
266
  const scriptContent = 'console.log("Script in body");';
267
267
  layout.script({ src: 'scriptbody.js' }, scriptContent, false);
268
- assert.strictEqual(layout.body.next.$('script').innerHTML, scriptContent, 'Script should be added to body');
268
+ assert.strictEqual(layout.body.next.innerHTML, scriptContent, 'Script should be added to body');
269
269
  });
270
270
 
271
271
  it('should append version parameter correctly when src already has parameters', () => {
@@ -328,7 +328,6 @@ describe('Url', () => {
328
328
  layout.url('not-a-url', 'aa');
329
329
  assert.strictEqual(layout.root.$('link[rel="canonical"]'), null, 'Canonical URL should not be added for invalid URLs');
330
330
  });
331
-
332
331
 
333
332
  it('should add url correctly', () => {
334
333
  const url = 'http://localhost';
@@ -426,4 +425,12 @@ describe('description and title', () => {
426
425
  assert(layout.root.$('[property="og:title"]').getAttribute('content') === title, 'Title not set correctly');
427
426
  });
428
427
 
428
+ it('should add title if no title tag', () => {
429
+ layout.$('title').remove()
430
+ const title = 'Test Title';
431
+ layout.title(title);
432
+ assert(layout.root.$('title').innerHTML === title, 'Title not set correctly');
433
+ assert(layout.root.$('[property="og:title"]').getAttribute('content') === title, 'Title not set correctly');
434
+ });
435
+
429
436
  });
@@ -47,7 +47,7 @@ describe('HTML Structure Initialization', () => {
47
47
  });
48
48
 
49
49
  it('should initialize html element correctly', () => {
50
- assert.strictEqual(layout.html.tagName, 'html', 'HTML element should be initialized');
50
+ assert.strictEqual(layout.html.tagName, 'HTML', 'HTML element should be initialized');
51
51
  });
52
52
 
53
53
  it('should not recreate html element if it already exists', () => {
@@ -56,7 +56,7 @@ describe('HTML Structure Initialization', () => {
56
56
  });
57
57
 
58
58
  it('should initialize body element correctly', () => {
59
- assert.strictEqual(layout.body.tagName, 'body', 'Body element should be initialized');
59
+ assert.strictEqual(layout.body.tagName, 'BODY', 'Body element should be initialized');
60
60
  });
61
61
 
62
62
  it('should not recreate body element if it already exists', () => {
@@ -65,7 +65,7 @@ describe('HTML Structure Initialization', () => {
65
65
  });
66
66
 
67
67
  it('should initialize head element correctly', () => {
68
- assert.strictEqual(layout.head.tagName, 'head', 'Head element should be initialized');
68
+ assert.strictEqual(layout.head.tagName, 'HEAD', 'Head element should be initialized');
69
69
  });
70
70
 
71
71
  it('should not recreate head element if it already exists', () => {
@@ -175,20 +175,15 @@ describe('Component Updating', () => {
175
175
 
176
176
  });
177
177
 
178
- describe('Cache and Clone Testing', () => {
178
+ describe('Clone Testing', () => {
179
179
  let layout;
180
180
  beforeEach(() => {
181
181
  layout = new Layout();
182
182
  });
183
183
 
184
- it('should retrieve cached version of the layout', () => {
185
- const cachedVersion = layout.cached;
186
- assert.doesNotThrow(() => JSON.stringify(cachedVersion)) // should be object without recursions
187
- assert(buildFromCache(cachedVersion).innerHTML === layout.rawHtml)
188
- });
189
-
190
184
  it('should clone the layout correctly', () => {
191
185
  const clone = layout.clone;
186
+ console.log(clone.constructor.name)
192
187
  assert(clone instanceof Layout, 'Clone should be an instance of Layout');
193
188
  assert.notStrictEqual(clone, layout, 'Clone should not be the same instance as the original');
194
189
  });
package/lib/build-root.js DELETED
@@ -1,16 +0,0 @@
1
- const { buildFromCache, Root, parseHTML, cacheDoc, Document } = require('als-document')
2
-
3
- function buildRoot(item) {
4
- const root =
5
- (item instanceof Root) ? buildFromCache(cacheDoc(item))
6
- : (typeof item === 'string') ? parseHTML(item)
7
- : (typeof item === 'object' && item.tagName) ? buildFromCache(item)
8
- : new Root()
9
-
10
- const firstNode = root.childNodes[0]
11
- if(!firstNode || firstNode.tagName !== '!DOCTYPE') {root.insert(1,/*html*/`<!DOCTYPE html>`)}
12
-
13
- return root
14
- }
15
-
16
- module.exports = buildRoot
@@ -1,2 +0,0 @@
1
- // https://www.iana.org//assignments/language-subtag-registry/language-subtag-registry
2
- module.exports = ["aa","ab","ae","af","ak","am","an","ar","as","av","ay","az","ba","be","bg","bh","bi","bm","bn","bo","br","bs","ca","ce","ch","co","cr","cs","cu","cv","cy","da","de","dv","dz","ee","el","en","eo","es","et","eu","fa","ff","fi","fj","fo","fr","fy","ga","gd","gl","gn","gu","gv","ha","he","hi","ho","hr","ht","hu","hy","hz","ia","id","ie","ig","ii","ik","in","io","is","it","iu","iw","ja","ji","jv","jw","ka","kg","ki","kj","kk","kl","km","kn","ko","kr","ks","ku","kv","kw","ky","la","lb","lg","li","ln","lo","lt","lu","lv","mg","mh","mi","mk","ml","mn","mo","mr","ms","mt","my","na","nb","nd","ne","ng","nl","nn","no","nr","nv","ny","oc","oj","om","or","os","pa","pi","pl","ps","pt","qu","rm","rn","ro","ru","rw","sa","sc","sd","se","sg","sh","si","sk","sl","sm","sn","so","sq","sr","ss","st","su","sv","sw","ta","te","tg","th","ti","tk","tl","tn","to","tr","ts","tt","tw","ty","ug","uk","ur","uz","ve","vi","vo","wa","wo","xh","yi","yo","za","zh","zu","aaa","aab","aac","aad","aae","aaf","aag","aah","aai","aak","aal","aam","aan","aao","aap","aaq","aas","aat","aau","aav","aaw","aax","aaz","aba","abb","abc","abd","abe","abf","abg","abh","abi","abj","abl","abm","abn","abo","abp","abq","abr","abs","abt","abu","abv","abw","abx","aby","abz","aca","acb","acd","ace","acf","ach","aci","ack","acl","acm","acn","acp","acq","acr","acs","act","acu","acv","acw","acx","acy","acz","ada","adb","add","ade","adf","adg","adh","adi","adj","adl","adn","ado","adp","adq","adr","ads","adt","adu","adw","adx","ady","adz","aea","aeb","aec","aed","aee","aek","ael","aem","aen","aeq","aer","aes","aeu","aew","aey","aez","afa","afb","afd","afe","afg","afh","afi","afk","afn","afo","afp","afs","aft","afu","afz","aga","agb","agc","agd","age","agf","agg","agh","agi","agj","agk","agl","agm","agn","ago","agp","agq","agr","ags","agt","agu","agv","agw","agx","agy","agz","aha","ahb","ahg","ahh","ahi","ahk","ahl","ahm","ahn","aho","ahp","ahr","ahs","aht","aia","aib","aic","aid","aie","aif","aig","aih","aii","aij","aik","ail","aim","ain","aio","aip","aiq","air","ais","ait","aiw","aix","aiy","aja","ajg","aji","ajn","ajp","ajs","ajt","aju","ajw","ajz","akb","akc","akd","ake","akf","akg","akh","aki","akj","akk","akl","akm","ako","akp","akq","akr","aks","akt","aku","akv","akw","akx","aky","akz","ala","alc","ald","ale","alf","alg","alh","ali","alj","alk","all","alm","aln","alo","alp","alq","alr","als","alt","alu","alv","alw","alx","aly","alz","ama","amb","amc","ame","amf","amg","ami","amj","amk","aml","amm","amn","amo","amp","amq","amr","ams","amt","amu","amv","amw","amx","amy","amz","ana","anb","anc","and","ane","anf","ang","anh","ani","anj","ank","anl","anm","ann","ano","anp","anq","anr","ans","ant","anu","anv","anw","anx","any","anz","aoa","aob","aoc","aod","aoe","aof","aog","aoh","aoi","aoj","aok","aol","aom","aon","aor","aos","aot","aou","aox","aoz","apa","apb","apc","apd","ape","apf","apg","aph","api","apj","apk","apl","apm","apn","apo","app","apq","apr","aps","apt","apu","apv","apw","apx","apy","apz","aqa","aqc","aqd","aqg","aqk","aql","aqm","aqn","aqp","aqr","aqt","aqz","arb","arc","ard","are","arh","ari","arj","ark","arl","arn","aro","arp","arq","arr","ars","art","aru","arv","arw","arx","ary","arz","asa","asb","asc","asd","ase","asf","asg","ash","asi","asj","ask","asl","asn","aso","asp","asq","asr","ass","ast","asu","asv","asw","asx","asy","asz","ata","atb","atc","atd","ate","atg","ath","ati","atj","atk","atl","atm","atn","ato","atp","atq","atr","ats","att","atu","atv","atw","atx","aty","atz","aua","aub","auc","aud","aue","auf","aug","auh","aui","auj","auk","aul","aum","aun","auo","aup","auq","aur","aus","aut","auu","auw","aux","auy","auz","avb","avd","avi","avk","avl","avm","avn","avo","avs","avt","avu","avv","awa","awb","awc","awd","awe","awg","awh","awi","awk","awm","awn","awo","awr","aws","awt","awu","awv","aww","awx","awy","axb","axe","axg","axk","axl","axm","axx","aya","ayb","ayc","ayd","aye","ayg","ayh","ayi","ayk","ayl","ayn","ayo","ayp","ayq","ayr","ays","ayt","ayu","ayx","ayy","ayz","aza","azb","azc","azd","azg","azj","azm","azn","azo","azt","azz","baa","bab","bac","bad","bae","baf","bag","bah","bai","baj","bal","ban","bao","bap","bar","bas","bat","bau","bav","baw","bax","bay","baz","bba","bbb","bbc","bbd","bbe","bbf","bbg","bbh","bbi","bbj","bbk","bbl","bbm","bbn","bbo","bbp","bbq","bbr","bbs","bbt","bbu","bbv","bbw","bbx","bby","bbz","bca","bcb","bcc","bcd","bce","bcf","bcg","bch","bci","bcj","bck","bcl","bcm","bcn","bco","bcp","bcq","bcr","bcs","bct","bcu","bcv","bcw","bcy","bcz","bda","bdb","bdc","bdd","bde","bdf","bdg","bdh","bdi","bdj","bdk","bdl","bdm","bdn","bdo","bdp","bdq","bdr","bds","bdt","bdu","bdv","bdw","bdx","bdy","bdz","bea","beb","bec","bed","bee","bef","beg","beh","bei","bej","bek","bem","beo","bep","beq","ber","bes","bet","beu","bev","bew","bex","bey","bez","bfa","bfb","bfc","bfd","bfe","bff","bfg","bfh","bfi","bfj","bfk","bfl","bfm","bfn","bfo","bfp","bfq","bfr","bfs","bft","bfu","bfw","bfx","bfy","bfz","bga","bgb","bgc","bgd","bge","bgf","bgg","bgi","bgj","bgk","bgl","bgm","bgn","bgo","bgp","bgq","bgr","bgs","bgt","bgu","bgv","bgw","bgx","bgy","bgz","bha","bhb","bhc","bhd","bhe","bhf","bhg","bhh","bhi","bhj","bhk","bhl","bhm","bhn","bho","bhp","bhq","bhr","bhs","bht","bhu","bhv","bhw","bhx","bhy","bhz","bia","bib","bic","bid","bie","bif","big","bij","bik","bil","bim","bin","bio","bip","biq","bir","bit","biu","biv","biw","bix","biy","biz","bja","bjb","bjc","bjd","bje","bjf","bjg","bjh","bji","bjj","bjk","bjl","bjm","bjn","bjo","bjp","bjq","bjr","bjs","bjt","bju","bjv","bjw","bjx","bjy","bjz","bka","bkb","bkc","bkd","bkf","bkg","bkh","bki","bkj","bkk","bkl","bkm","bkn","bko","bkp","bkq","bkr","bks","bkt","bku","bkv","bkw","bkx","bky","bkz","bla","blb","blc","bld","ble","blf","blg","blh","bli","blj","blk","bll","blm","bln","blo","blp","blq","blr","bls","blt","blv","blw","blx","bly","blz","bma","bmb","bmc","bmd","bme","bmf","bmg","bmh","bmi","bmj","bmk","bml","bmm","bmn","bmo","bmp","bmq","bmr","bms","bmt","bmu","bmv","bmw","bmx","bmy","bmz","bna","bnb","bnc","bnd","bne","bnf","bng","bni","bnj","bnk","bnl","bnm","bnn","bno","bnp","bnq","bnr","bns","bnt","bnu","bnv","bnw","bnx","bny","bnz","boa","bob","boe","bof","bog","boh","boi","boj","bok","bol","bom","bon","boo","bop","boq","bor","bot","bou","bov","bow","box","boy","boz","bpa","bpb","bpc","bpd","bpe","bpg","bph","bpi","bpj","bpk","bpl","bpm","bpn","bpo","bpp","bpq","bpr","bps","bpt","bpu","bpv","bpw","bpx","bpy","bpz","bqa","bqb","bqc","bqd","bqf","bqg","bqh","bqi","bqj","bqk","bql","bqm","bqn","bqo","bqp","bqq","bqr","bqs","bqt","bqu","bqv","bqw","bqx","bqy","bqz","bra","brb","brc","brd","brf","brg","brh","bri","brj","brk","brl","brm","brn","bro","brp","brq","brr","brs","brt","bru","brv","brw","brx","bry","brz","bsa","bsb","bsc","bse","bsf","bsg","bsh","bsi","bsj","bsk","bsl","bsm","bsn","bso","bsp","bsq","bsr","bss","bst","bsu","bsv","bsw","bsx","bsy","bta","btb","btc","btd","bte","btf","btg","bth","bti","btj","btk","btl","btm","btn","bto","btp","btq","btr","bts","btt","btu","btv","btw","btx","bty","btz","bua","bub","buc","bud","bue","buf","bug","buh","bui","buj","buk","bum","bun","buo","bup","buq","bus","but","buu","buv","buw","bux","buy","buz","bva","bvb","bvc","bvd","bve","bvf","bvg","bvh","bvi","bvj","bvk","bvl","bvm","bvn","bvo","bvp","bvq","bvr","bvt","bvu","bvv","bvw","bvx","bvy","bvz","bwa","bwb","bwc","bwd","bwe","bwf","bwg","bwh","bwi","bwj","bwk","bwl","bwm","bwn","bwo","bwp","bwq","bwr","bws","bwt","bwu","bww","bwx","bwy","bwz","bxa","bxb","bxc","bxd","bxe","bxf","bxg","bxh","bxi","bxj","bxk","bxl","bxm","bxn","bxo","bxp","bxq","bxr","bxs","bxu","bxv","bxw","bxx","bxz","bya","byb","byc","byd","bye","byf","byg","byh","byi","byj","byk","byl","bym","byn","byo","byp","byq","byr","bys","byt","byv","byw","byx","byy","byz","bza","bzb","bzc","bzd","bze","bzf","bzg","bzh","bzi","bzj","bzk","bzl","bzm","bzn","bzo","bzp","bzq","bzr","bzs","bzt","bzu","bzv","bzw","bzx","bzy","bzz","caa","cab","cac","cad","cae","caf","cag","cah","cai","caj","cak","cal","cam","can","cao","cap","caq","car","cas","cau","cav","caw","cax","cay","caz","cba","cbb","cbc","cbd","cbe","cbg","cbh","cbi","cbj","cbk","cbl","cbn","cbo","cbq","cbr","cbs","cbt","cbu","cbv","cbw","cby","cca","ccc","ccd","cce","ccg","cch","ccj","ccl","ccm","ccn","cco","ccp","ccq","ccr","ccs","cda","cdc","cdd","cde","cdf","cdg","cdh","cdi","cdj","cdm","cdn","cdo","cdr","cds","cdy","cdz","cea","ceb","ceg","cek","cel","cen","cet","cey","cfa","cfd","cfg","cfm","cga","cgc","cgg","cgk","chb","chc","chd","chf","chg","chh","chj","chk","chl","chm","chn","cho","chp","chq","chr","cht","chw","chx","chy","chz","cia","cib","cic","cid","cie","cih","cik","cim","cin","cip","cir","ciw","ciy","cja","cje","cjh","cji","cjk","cjm","cjn","cjo","cjp","cjr","cjs","cjv","cjy","cka","ckb","ckh","ckl","ckm","ckn","cko","ckq","ckr","cks","ckt","cku","ckv","ckx","cky","ckz","cla","clc","cld","cle","clh","cli","clj","clk","cll","clm","clo","cls","clt","clu","clw","cly","cma","cmc","cme","cmg","cmi","cmk","cml","cmm","cmn","cmo","cmr","cms","cmt","cna","cnb","cnc","cng","cnh","cni","cnk","cnl","cno","cnp","cnq","cnr","cns","cnt","cnu","cnw","cnx","coa","cob","coc","cod","coe","cof","cog","coh","coj","cok","col","com","con","coo","cop","coq","cot","cou","cov","cow","cox","coy","coz","cpa","cpb","cpc","cpe","cpf","cpg","cpi","cpn","cpo","cpp","cps","cpu","cpx","cpy","cqd","cqu","cra","crb","crc","crd","crf","crg","crh","cri","crj","crk","crl","crm","crn","cro","crp","crq","crr","crs","crt","crv","crw","crx","cry","crz","csa","csb","csc","csd","cse","csf","csg","csh","csi","csj","csk","csl","csm","csn","cso","csp","csq","csr","css","cst","csu","csv","csw","csx","csy","csz","cta","ctc","ctd","cte","ctg","cth","ctl","ctm","ctn","cto","ctp","cts","ctt","ctu","cty","ctz","cua","cub","cuc","cug","cuh","cui","cuj","cuk","cul","cum","cuo","cup","cuq","cur","cus","cut","cuu","cuv","cuw","cux","cuy","cvg","cvn","cwa","cwb","cwd","cwe","cwg","cwt","cxh","cya","cyb","cyo","czh","czk","czn","czo","czt","daa","dac","dad","dae","daf","dag","dah","dai","daj","dak","dal","dam","dao","dap","daq","dar","das","dau","dav","daw","dax","day","daz","dba","dbb","dbd","dbe","dbf","dbg","dbi","dbj","dbl","dbm","dbn","dbo","dbp","dbq","dbr","dbt","dbu","dbv","dbw","dby","dcc","dcr","dda","ddd","dde","ddg","ddi","ddj","ddn","ddo","ddr","dds","ddw","dec","ded","dee","def","deg","deh","dei","dek","del","dem","den","dep","deq","der","des","dev","dez","dga","dgb","dgc","dgd","dge","dgg","dgh","dgi","dgk","dgl","dgn","dgo","dgr","dgs","dgt","dgu","dgw","dgx","dgz","dha","dhd","dhg","dhi","dhl","dhm","dhn","dho","dhr","dhs","dhu","dhv","dhw","dhx","dia","dib","dic","did","dif","dig","dih","dii","dij","dik","dil","dim","din","dio","dip","diq","dir","dis","dit","diu","diw","dix","diy","diz","dja","djb","djc","djd","dje","djf","dji","djj","djk","djl","djm","djn","djo","djr","dju","djw","dka","dkg","dkk","dkl","dkr","dks","dkx","dlg","dlk","dlm","dln","dma","dmb","dmc","dmd","dme","dmf","dmg","dmk","dml","dmm","dmn","dmo","dmr","dms","dmu","dmv","dmw","dmx","dmy","dna","dnd","dne","dng","dni","dnj","dnk","dnn","dno","dnr","dnt","dnu","dnv","dnw","dny","doa","dob","doc","doe","dof","doh","doi","dok","dol","don","doo","dop","doq","dor","dos","dot","dov","dow","dox","doy","doz","dpp","dra","drb","drc","drd","dre","drg","drh","dri","drl","drn","dro","drq","drr","drs","drt","dru","drw","dry","dsb","dse","dsh","dsi","dsk","dsl","dsn","dso","dsq","dsz","dta","dtb","dtd","dth","dti","dtk","dtm","dtn","dto","dtp","dtr","dts","dtt","dtu","dty","dua","dub","duc","dud","due","duf","dug","duh","dui","duj","duk","dul","dum","dun","duo","dup","duq","dur","dus","duu","duv","duw","dux","duy","duz","dva","dwa","dwk","dwl","dwr","dws","dwu","dww","dwy","dwz","dya","dyb","dyd","dyg","dyi","dym","dyn","dyo","dyr","dyu","dyy","dza","dzd","dze","dzg","dzl","dzn","eaa","ebc","ebg","ebk","ebo","ebr","ebu","ecr","ecs","ecy","eee","efa","efe","efi","ega","egl","egm","ego","egx","egy","ehs","ehu","eip","eit","eiv","eja","eka","ekc","eke","ekg","eki","ekk","ekl","ekm","eko","ekp","ekr","eky","ele","elh","eli","elk","elm","elo","elp","elu","elx","ema","emb","eme","emg","emi","emk","emm","emn","emo","emp","emq","ems","emu","emw","emx","emy","emz","ena","enb","enc","end","enf","enh","enl","enm","enn","eno","enq","enr","enu","env","enw","enx","eot","epi","era","erg","erh","eri","erk","ero","err","ers","ert","erw","ese","esg","esh","esi","esk","esl","esm","esn","eso","esq","ess","esu","esx","esy","etb","etc","eth","etn","eto","etr","ets","ett","etu","etx","etz","eud","euq","eve","evh","evn","ewo","ext","eya","eyo","eza","eze","faa","fab","fad","faf","fag","fah","fai","faj","fak","fal","fam","fan","fap","far","fat","fau","fax","fay","faz","fbl","fcs","fer","ffi","ffm","fgr","fia","fie","fif","fil","fip","fir","fit","fiu","fiw","fkk","fkv","fla","flh","fli","fll","fln","flr","fly","fmp","fmu","fnb","fng","fni","fod","foi","fom","fon","for","fos","fox","fpe","fqs","frc","frd","frk","frm","fro","frp","frq","frr","frs","frt","fse","fsl","fss","fub","fuc","fud","fue","fuf","fuh","fui","fuj","fum","fun","fuq","fur","fut","fuu","fuv","fuy","fvr","fwa","fwe","gaa","gab","gac","gad","gae","gaf","gag","gah","gai","gaj","gak","gal","gam","gan","gao","gap","gaq","gar","gas","gat","gau","gav","gaw","gax","gay","gaz","gba","gbb","gbc","gbd","gbe","gbf","gbg","gbh","gbi","gbj","gbk","gbl","gbm","gbn","gbo","gbp","gbq","gbr","gbs","gbu","gbv","gbw","gbx","gby","gbz","gcc","gcd","gce","gcf","gcl","gcn","gcr","gct","gda","gdb","gdc","gdd","gde","gdf","gdg","gdh","gdi","gdj","gdk","gdl","gdm","gdn","gdo","gdq","gdr","gds","gdt","gdu","gdx","gea","geb","gec","ged","gef","geg","geh","gei","gej","gek","gel","gem","geq","ges","gev","gew","gex","gey","gez","gfk","gft","gfx","gga","ggb","ggd","gge","ggg","ggk","ggl","ggn","ggo","ggr","ggt","ggu","ggw","gha","ghc","ghe","ghh","ghk","ghl","ghn","gho","ghr","ghs","ght","gia","gib","gic","gid","gie","gig","gih","gii","gil","gim","gin","gio","gip","giq","gir","gis","git","giu","giw","gix","giy","giz","gji","gjk","gjm","gjn","gjr","gju","gka","gkd","gke","gkn","gko","gkp","gku","glb","glc","gld","glh","gli","glj","glk","gll","glo","glr","glu","glw","gly","gma","gmb","gmd","gme","gmg","gmh","gml","gmm","gmn","gmq","gmr","gmu","gmv","gmw","gmx","gmy","gmz","gna","gnb","gnc","gnd","gne","gng","gnh","gni","gnj","gnk","gnl","gnm","gnn","gno","gnq","gnr","gnt","gnu","gnw","gnz","goa","gob","goc","god","goe","gof","gog","goh","goi","goj","gok","gol","gom","gon","goo","gop","goq","gor","gos","got","gou","gov","gow","gox","goy","goz","gpa","gpe","gpn","gqa","gqi","gqn","gqr","gqu","gra","grb","grc","grd","grg","grh","gri","grj","grk","grm","gro","grq","grr","grs","grt","gru","grv","grw","grx","gry","grz","gse","gsg","gsl","gsm","gsn","gso","gsp","gss","gsw","gta","gti","gtu","gua","gub","guc","gud","gue","guf","gug","guh","gui","guk","gul","gum","gun","guo","gup","guq","gur","gus","gut","guu","guv","guw","gux","guz","gva","gvc","gve","gvf","gvj","gvl","gvm","gvn","gvo","gvp","gvr","gvs","gvy","gwa","gwb","gwc","gwd","gwe","gwf","gwg","gwi","gwj","gwm","gwn","gwr","gwt","gwu","gww","gwx","gxx","gya","gyb","gyd","gye","gyf","gyg","gyi","gyl","gym","gyn","gyo","gyr","gyy","gyz","gza","gzi","gzn","haa","hab","hac","had","hae","haf","hag","hah","hai","haj","hak","hal","ham","han","hao","hap","haq","har","has","hav","haw","hax","hay","haz","hba","hbb","hbn","hbo","hbu","hca","hch","hdn","hds","hdy","hea","hed","heg","heh","hei","hem","hgm","hgw","hhi","hhr","hhy","hia","hib","hid","hif","hig","hih","hii","hij","hik","hil","him","hio","hir","hit","hiw","hix","hji","hka","hke","hkh","hkk","hkn","hks","hla","hlb","hld","hle","hlt","hlu","hma","hmb","hmc","hmd","hme","hmf","hmg","hmh","hmi","hmj","hmk","hml","hmm","hmn","hmp","hmq","hmr","hms","hmt","hmu","hmv","hmw","hmx","hmy","hmz","hna","hnd","hne","hng","hnh","hni","hnj","hnn","hno","hns","hnu","hoa","hob","hoc","hod","hoe","hoh","hoi","hoj","hok","hol","hom","hoo","hop","hor","hos","hot","hov","how","hoy","hoz","hpo","hps","hra","hrc","hre","hrk","hrm","hro","hrp","hrr","hrt","hru","hrw","hrx","hrz","hsb","hsh","hsl","hsn","hss","hti","hto","hts","htu","htx","hub","huc","hud","hue","huf","hug","huh","hui","huj","huk","hul","hum","huo","hup","huq","hur","hus","hut","huu","huv","huw","hux","huy","huz","hvc","hve","hvk","hvn","hvv","hwa","hwc","hwo","hya","hyw","hyx","iai","ian","iap","iar","iba","ibb","ibd","ibe","ibg","ibh","ibi","ibl","ibm","ibn","ibr","ibu","iby","ica","ich","icl","icr","ida","idb","idc","idd","ide","idi","idr","ids","idt","idu","ifa","ifb","ife","iff","ifk","ifm","ifu","ify","igb","ige","igg","igl","igm","ign","igo","igs","igw","ihb","ihi","ihp","ihw","iin","iir","ijc","ije","ijj","ijn","ijo","ijs","ike","ikh","iki","ikk","ikl","iko","ikp","ikr","iks","ikt","ikv","ikw","ikx","ikz","ila","ilb","ilg","ili","ilk","ill","ilm","ilo","ilp","ils","ilu","ilv","ilw","ima","ime","imi","iml","imn","imo","imr","ims","imt","imy","inb","inc","ine","ing","inh","inj","inl","inm","inn","ino","inp","ins","int","inz","ior","iou","iow","ipi","ipo","iqu","iqw","ira","ire","irh","iri","irk","irn","iro","irr","iru","irx","iry","isa","isc","isd","ise","isg","ish","isi","isk","ism","isn","iso","isr","ist","isu","itb","itc","itd","ite","iti","itk","itl","itm","ito","itr","its","itt","itv","itw","itx","ity","itz","ium","ivb","ivv","iwk","iwm","iwo","iws","ixc","ixl","iya","iyo","iyx","izh","izi","izm","izr","izz","jaa","jab","jac","jad","jae","jaf","jah","jaj","jak","jal","jam","jan","jao","jaq","jar","jas","jat","jau","jax","jay","jaz","jbe","jbi","jbj","jbk","jbm","jbn","jbo","jbr","jbt","jbu","jbw","jcs","jct","jda","jdg","jdt","jeb","jee","jeg","jeh","jei","jek","jel","jen","jer","jet","jeu","jgb","jge","jgk","jgo","jhi","jhs","jia","jib","jic","jid","jie","jig","jih","jii","jil","jim","jio","jiq","jit","jiu","jiv","jiy","jje","jjr","jka","jkm","jko","jkp","jkr","jks","jku","jle","jls","jma","jmb","jmc","jmd","jmi","jml","jmn","jmr","jms","jmw","jmx","jna","jnd","jng","jni","jnj","jnl","jns","job","jod","jog","jor","jos","jow","jpa","jpr","jpx","jqr","jra","jrb","jrr","jrt","jru","jsl","jua","jub","juc","jud","juh","jui","juk","jul","jum","jun","juo","jup","jur","jus","jut","juu","juw","juy","jvd","jvn","jwi","jya","jye","jyy","kaa","kab","kac","kad","kae","kaf","kag","kah","kai","kaj","kak","kam","kao","kap","kaq","kar","kav","kaw","kax","kay","kba","kbb","kbc","kbd","kbe","kbf","kbg","kbh","kbi","kbj","kbk","kbl","kbm","kbn","kbo","kbp","kbq","kbr","kbs","kbt","kbu","kbv","kbw","kbx","kby","kbz","kca","kcb","kcc","kcd","kce","kcf","kcg","kch","kci","kcj","kck","kcl","kcm","kcn","kco","kcp","kcq","kcr","kcs","kct","kcu","kcv","kcw","kcx","kcy","kcz","kda","kdc","kdd","kde","kdf","kdg","kdh","kdi","kdj","kdk","kdl","kdm","kdn","kdo","kdp","kdq","kdr","kdt","kdu","kdv","kdw","kdx","kdy","kdz","kea","keb","kec","ked","kee","kef","keg","keh","kei","kej","kek","kel","kem","ken","keo","kep","keq","ker","kes","ket","keu","kev","kew","kex","key","kez","kfa","kfb","kfc","kfd","kfe","kff","kfg","kfh","kfi","kfj","kfk","kfl","kfm","kfn","kfo","kfp","kfq","kfr","kfs","kft","kfu","kfv","kfw","kfx","kfy","kfz","kga","kgb","kgc","kgd","kge","kgf","kgg","kgh","kgi","kgj","kgk","kgl","kgm","kgn","kgo","kgp","kgq","kgr","kgs","kgt","kgu","kgv","kgw","kgx","kgy","kha","khb","khc","khd","khe","khf","khg","khh","khi","khj","khk","khl","khn","kho","khp","khq","khr","khs","kht","khu","khv","khw","khx","khy","khz","kia","kib","kic","kid","kie","kif","kig","kih","kii","kij","kil","kim","kio","kip","kiq","kis","kit","kiu","kiv","kiw","kix","kiy","kiz","kja","kjb","kjc","kjd","kje","kjf","kjg","kjh","kji","kjj","kjk","kjl","kjm","kjn","kjo","kjp","kjq","kjr","kjs","kjt","kju","kjv","kjx","kjy","kjz","kka","kkb","kkc","kkd","kke","kkf","kkg","kkh","kki","kkj","kkk","kkl","kkm","kkn","kko","kkp","kkq","kkr","kks","kkt","kku","kkv","kkw","kkx","kky","kkz","kla","klb","klc","kld","kle","klf","klg","klh","kli","klj","klk","kll","klm","kln","klo","klp","klq","klr","kls","klt","klu","klv","klw","klx","kly","klz","kma","kmb","kmc","kmd","kme","kmf","kmg","kmh","kmi","kmj","kmk","kml","kmm","kmn","kmo","kmp","kmq","kmr","kms","kmt","kmu","kmv","kmw","kmx","kmy","kmz","kna","knb","knc","knd","kne","knf","kng","kni","knj","knk","knl","knm","knn","kno","knp","knq","knr","kns","knt","knu","knv","knw","knx","kny","knz","koa","koc","kod","koe","kof","kog","koh","koi","koj","kok","kol","koo","kop","koq","kos","kot","kou","kov","kow","kox","koy","koz","kpa","kpb","kpc","kpd","kpe","kpf","kpg","kph","kpi","kpj","kpk","kpl","kpm","kpn","kpo","kpp","kpq","kpr","kps","kpt","kpu","kpv","kpw","kpx","kpy","kpz","kqa","kqb","kqc","kqd","kqe","kqf","kqg","kqh","kqi","kqj","kqk","kql","kqm","kqn","kqo","kqp","kqq","kqr","kqs","kqt","kqu","kqv","kqw","kqx","kqy","kqz","kra","krb","krc","krd","kre","krf","krh","kri","krj","krk","krl","krm","krn","kro","krp","krr","krs","krt","kru","krv","krw","krx","kry","krz","ksa","ksb","ksc","ksd","kse","ksf","ksg","ksh","ksi","ksj","ksk","ksl","ksm","ksn","kso","ksp","ksq","ksr","kss","kst","ksu","ksv","ksw","ksx","ksy","ksz","kta","ktb","ktc","ktd","kte","ktf","ktg","kth","kti","ktj","ktk","ktl","ktm","ktn","kto","ktp","ktq","ktr","kts","ktt","ktu","ktv","ktw","ktx","kty","ktz","kub","kuc","kud","kue","kuf","kug","kuh","kui","kuj","kuk","kul","kum","kun","kuo","kup","kuq","kus","kut","kuu","kuv","kuw","kux","kuy","kuz","kva","kvb","kvc","kvd","kve","kvf","kvg","kvh","kvi","kvj","kvk","kvl","kvm","kvn","kvo","kvp","kvq","kvr","kvs","kvt","kvu","kvv","kvw","kvx","kvy","kvz","kwa","kwb","kwc","kwd","kwe","kwf","kwg","kwh","kwi","kwj","kwk","kwl","kwm","kwn","kwo","kwp","kwq","kwr","kws","kwt","kwu","kwv","kww","kwx","kwy","kwz","kxa","kxb","kxc","kxd","kxe","kxf","kxh","kxi","kxj","kxk","kxl","kxm","kxn","kxo","kxp","kxq","kxr","kxs","kxt","kxu","kxv","kxw","kxx","kxy","kxz","kya","kyb","kyc","kyd","kye","kyf","kyg","kyh","kyi","kyj","kyk","kyl","kym","kyn","kyo","kyp","kyq","kyr","kys","kyt","kyu","kyv","kyw","kyx","kyy","kyz","kza","kzb","kzc","kzd","kze","kzf","kzg","kzh","kzi","kzj","kzk","kzl","kzm","kzn","kzo","kzp","kzq","kzr","kzs","kzt","kzu","kzv","kzw","kzx","kzy","kzz","laa","lab","lac","lad","lae","laf","lag","lah","lai","laj","lak","lal","lam","lan","lap","laq","lar","las","lau","law","lax","lay","laz","lba","lbb","lbc","lbe","lbf","lbg","lbi","lbj","lbk","lbl","lbm","lbn","lbo","lbq","lbr","lbs","lbt","lbu","lbv","lbw","lbx","lby","lbz","lcc","lcd","lce","lcf","lch","lcl","lcm","lcp","lcq","lcs","lda","ldb","ldd","ldg","ldh","ldi","ldj","ldk","ldl","ldm","ldn","ldo","ldp","ldq","lea","leb","lec","led","lee","lef","leg","leh","lei","lej","lek","lel","lem","len","leo","lep","leq","ler","les","let","leu","lev","lew","lex","ley","lez","lfa","lfn","lga","lgb","lgg","lgh","lgi","lgk","lgl","lgm","lgn","lgo","lgq","lgr","lgs","lgt","lgu","lgz","lha","lhh","lhi","lhl","lhm","lhn","lhp","lhs","lht","lhu","lia","lib","lic","lid","lie","lif","lig","lih","lii","lij","lik","lil","lio","lip","liq","lir","lis","liu","liv","liw","lix","liy","liz","lja","lje","lji","ljl","ljp","ljw","ljx","lka","lkb","lkc","lkd","lke","lkh","lki","lkj","lkl","lkm","lkn","lko","lkr","lks","lkt","lku","lky","lla","llb","llc","lld","lle","llf","llg","llh","lli","llj","llk","lll","llm","lln","llo","llp","llq","lls","llu","llx","lma","lmb","lmc","lmd","lme","lmf","lmg","lmh","lmi","lmj","lmk","lml","lmm","lmn","lmo","lmp","lmq","lmr","lmu","lmv","lmw","lmx","lmy","lmz","lna","lnb","lnd","lng","lnh","lni","lnj","lnl","lnm","lnn","lno","lns","lnu","lnw","lnz","loa","lob","loc","loe","lof","log","loh","loi","loj","lok","lol","lom","lon","loo","lop","loq","lor","los","lot","lou","lov","low","lox","loy","loz","lpa","lpe","lpn","lpo","lpx","lqr","lra","lrc","lre","lrg","lri","lrk","lrl","lrm","lrn","lro","lrr","lrt","lrv","lrz","lsa","lsb","lsc","lsd","lse","lsg","lsh","lsi","lsl","lsm","lsn","lso","lsp","lsr","lss","lst","lsv","lsw","lsy","ltc","ltg","lth","lti","ltn","lto","lts","ltu","lua","luc","lud","lue","luf","lui","luj","luk","lul","lum","lun","luo","lup","luq","lur","lus","lut","luu","luv","luw","luy","luz","lva","lvi","lvk","lvl","lvs","lvu","lwa","lwe","lwg","lwh","lwl","lwm","lwo","lws","lwt","lwu","lww","lxm","lya","lyg","lyn","lzh","lzl","lzn","lzz","maa","mab","mad","mae","maf","mag","mai","maj","mak","mam","man","map","maq","mas","mat","mau","mav","maw","max","maz","mba","mbb","mbc","mbd","mbe","mbf","mbh","mbi","mbj","mbk","mbl","mbm","mbn","mbo","mbp","mbq","mbr","mbs","mbt","mbu","mbv","mbw","mbx","mby","mbz","mca","mcb","mcc","mcd","mce","mcf","mcg","mch","mci","mcj","mck","mcl","mcm","mcn","mco","mcp","mcq","mcr","mcs","mct","mcu","mcv","mcw","mcx","mcy","mcz","mda","mdb","mdc","mdd","mde","mdf","mdg","mdh","mdi","mdj","mdk","mdl","mdm","mdn","mdp","mdq","mdr","mds","mdt","mdu","mdv","mdw","mdx","mdy","mdz","mea","meb","mec","med","mee","mef","meg","meh","mei","mej","mek","mel","mem","men","meo","mep","meq","mer","mes","met","meu","mev","mew","mey","mez","mfa","mfb","mfc","mfd","mfe","mff","mfg","mfh","mfi","mfj","mfk","mfl","mfm","mfn","mfo","mfp","mfq","mfr","mfs","mft","mfu","mfv","mfw","mfx","mfy","mfz","mga","mgb","mgc","mgd","mge","mgf","mgg","mgh","mgi","mgj","mgk","mgl","mgm","mgn","mgo","mgp","mgq","mgr","mgs","mgt","mgu","mgv","mgw","mgx","mgy","mgz","mha","mhb","mhc","mhd","mhe","mhf","mhg","mhh","mhi","mhj","mhk","mhl","mhm","mhn","mho","mhp","mhq","mhr","mhs","mht","mhu","mhw","mhx","mhy","mhz","mia","mib","mic","mid","mie","mif","mig","mih","mii","mij","mik","mil","mim","min","mio","mip","miq","mir","mis","mit","miu","miw","mix","miy","miz","mja","mjb","mjc","mjd","mje","mjg","mjh","mji","mjj","mjk","mjl","mjm","mjn","mjo","mjp","mjq","mjr","mjs","mjt","mju","mjv","mjw","mjx","mjy","mjz","mka","mkb","mkc","mke","mkf","mkg","mkh","mki","mkj","mkk","mkl","mkm","mkn","mko","mkp","mkq","mkr","mks","mkt","mku","mkv","mkw","mkx","mky","mkz","mla","mlb","mlc","mld","mle","mlf","mlh","mli","mlj","mlk","mll","mlm","mln","mlo","mlp","mlq","mlr","mls","mlu","mlv","mlw","mlx","mlz","mma","mmb","mmc","mmd","mme","mmf","mmg","mmh","mmi","mmj","mmk","mml","mmm","mmn","mmo","mmp","mmq","mmr","mmt","mmu","mmv","mmw","mmx","mmy","mmz","mna","mnb","mnc","mnd","mne","mnf","mng","mnh","mni","mnj","mnk","mnl","mnm","mnn","mno","mnp","mnq","mnr","mns","mnt","mnu","mnv","mnw","mnx","mny","mnz","moa","moc","mod","moe","mof","mog","moh","moi","moj","mok","mom","moo","mop","moq","mor","mos","mot","mou","mov","mow","mox","moy","moz","mpa","mpb","mpc","mpd","mpe","mpg","mph","mpi","mpj","mpk","mpl","mpm","mpn","mpo","mpp","mpq","mpr","mps","mpt","mpu","mpv","mpw","mpx","mpy","mpz","mqa","mqb","mqc","mqe","mqf","mqg","mqh","mqi","mqj","mqk","mql","mqm","mqn","mqo","mqp","mqq","mqr","mqs","mqt","mqu","mqv","mqw","mqx","mqy","mqz","mra","mrb","mrc","mrd","mre","mrf","mrg","mrh","mrj","mrk","mrl","mrm","mrn","mro","mrp","mrq","mrr","mrs","mrt","mru","mrv","mrw","mrx","mry","mrz","msb","msc","msd","mse","msf","msg","msh","msi","msj","msk","msl","msm","msn","mso","msp","msq","msr","mss","mst","msu","msv","msw","msx","msy","msz","mta","mtb","mtc","mtd","mte","mtf","mtg","mth","mti","mtj","mtk","mtl","mtm","mtn","mto","mtp","mtq","mtr","mts","mtt","mtu","mtv","mtw","mtx","mty","mua","mub","muc","mud","mue","mug","muh","mui","muj","muk","mul","mum","mun","muo","mup","muq","mur","mus","mut","muu","muv","mux","muy","muz","mva","mvb","mvd","mve","mvf","mvg","mvh","mvi","mvk","mvl","mvm","mvn","mvo","mvp","mvq","mvr","mvs","mvt","mvu","mvv","mvw","mvx","mvy","mvz","mwa","mwb","mwc","mwd","mwe","mwf","mwg","mwh","mwi","mwj","mwk","mwl","mwm","mwn","mwo","mwp","mwq","mwr","mws","mwt","mwu","mwv","mww","mwx","mwy","mwz","mxa","mxb","mxc","mxd","mxe","mxf","mxg","mxh","mxi","mxj","mxk","mxl","mxm","mxn","mxo","mxp","mxq","mxr","mxs","mxt","mxu","mxv","mxw","mxx","mxy","mxz","myb","myc","myd","mye","myf","myg","myh","myi","myj","myk","myl","mym","myn","myo","myp","myq","myr","mys","myt","myu","myv","myw","myx","myy","myz","mza","mzb","mzc","mzd","mze","mzg","mzh","mzi","mzj","mzk","mzl","mzm","mzn","mzo","mzp","mzq","mzr","mzs","mzt","mzu","mzv","mzw","mzx","mzy","mzz","naa","nab","nac","nad","nae","naf","nag","nah","nai","naj","nak","nal","nam","nan","nao","nap","naq","nar","nas","nat","naw","nax","nay","naz","nba","nbb","nbc","nbd","nbe","nbf","nbg","nbh","nbi","nbj","nbk","nbm","nbn","nbo","nbp","nbq","nbr","nbs","nbt","nbu","nbv","nbw","nbx","nby","nca","ncb","ncc","ncd","nce","ncf","ncg","nch","nci","ncj","nck","ncl","ncm","ncn","nco","ncp","ncq","ncr","ncs","nct","ncu","ncx","ncz","nda","ndb","ndc","ndd","ndf","ndg","ndh","ndi","ndj","ndk","ndl","ndm","ndn","ndp","ndq","ndr","nds","ndt","ndu","ndv","ndw","ndx","ndy","ndz","nea","neb","nec","ned","nee","nef","neg","neh","nei","nej","nek","nem","nen","neo","neq","ner","nes","net","neu","nev","new","nex","ney","nez","nfa","nfd","nfl","nfr","nfu","nga","ngb","ngc","ngd","nge","ngf","ngg","ngh","ngi","ngj","ngk","ngl","ngm","ngn","ngo","ngp","ngq","ngr","ngs","ngt","ngu","ngv","ngw","ngx","ngy","ngz","nha","nhb","nhc","nhd","nhe","nhf","nhg","nhh","nhi","nhk","nhm","nhn","nho","nhp","nhq","nhr","nht","nhu","nhv","nhw","nhx","nhy","nhz","nia","nib","nic","nid","nie","nif","nig","nih","nii","nij","nik","nil","nim","nin","nio","niq","nir","nis","nit","niu","niv","niw","nix","niy","niz","nja","njb","njd","njh","nji","njj","njl","njm","njn","njo","njr","njs","njt","nju","njx","njy","njz","nka","nkb","nkc","nkd","nke","nkf","nkg","nkh","nki","nkj","nkk","nkm","nkn","nko","nkp","nkq","nkr","nks","nkt","nku","nkv","nkw","nkx","nkz","nla","nlc","nle","nlg","nli","nlj","nlk","nll","nlm","nln","nlo","nlq","nlr","nlu","nlv","nlw","nlx","nly","nlz","nma","nmb","nmc","nmd","nme","nmf","nmg","nmh","nmi","nmj","nmk","nml","nmm","nmn","nmo","nmp","nmq","nmr","nms","nmt","nmu","nmv","nmw","nmx","nmy","nmz","nna","nnb","nnc","nnd","nne","nnf","nng","nnh","nni","nnj","nnk","nnl","nnm","nnn","nnp","nnq","nnr","nns","nnt","nnu","nnv","nnw","nnx","nny","nnz","noa","noc","nod","noe","nof","nog","noh","noi","noj","nok","nol","nom","non","noo","nop","noq","nos","not","nou","nov","now","noy","noz","npa","npb","npg","nph","npi","npl","npn","npo","nps","npu","npx","npy","nqg","nqk","nql","nqm","nqn","nqo","nqq","nqt","nqy","nra","nrb","nrc","nre","nrf","nrg","nri","nrk","nrl","nrm","nrn","nrp","nrr","nrt","nru","nrx","nrz","nsa","nsb","nsc","nsd","nse","nsf","nsg","nsh","nsi","nsk","nsl","nsm","nsn","nso","nsp","nsq","nsr","nss","nst","nsu","nsv","nsw","nsx","nsy","nsz","ntd","nte","ntg","nti","ntj","ntk","ntm","nto","ntp","ntr","nts","ntu","ntw","ntx","nty","ntz","nua","nub","nuc","nud","nue","nuf","nug","nuh","nui","nuj","nuk","nul","num","nun","nuo","nup","nuq","nur","nus","nut","nuu","nuv","nuw","nux","nuy","nuz","nvh","nvm","nvo","nwa","nwb","nwc","nwe","nwg","nwi","nwm","nwo","nwr","nww","nwx","nwy","nxa","nxd","nxe","nxg","nxi","nxk","nxl","nxm","nxn","nxo","nxq","nxr","nxu","nxx","nyb","nyc","nyd","nye","nyf","nyg","nyh","nyi","nyj","nyk","nyl","nym","nyn","nyo","nyp","nyq","nyr","nys","nyt","nyu","nyv","nyw","nyx","nyy","nza","nzb","nzd","nzi","nzk","nzm","nzr","nzs","nzu","nzy","nzz","oaa","oac","oar","oav","obi","obk","obl","obm","obo","obr","obt","obu","oca","och","ocm","oco","ocu","oda","odk","odt","odu","ofo","ofs","ofu","ogb","ogc","oge","ogg","ogo","ogu","oht","ohu","oia","oie","oin","ojb","ojc","ojg","ojp","ojs","ojv","ojw","oka","okb","okc","okd","oke","okg","okh","oki","okj","okk","okl","okm","okn","oko","okr","oks","oku","okv","okx","okz","ola","old","ole","olk","olm","olo","olr","olt","olu","oma","omb","omc","ome","omg","omi","omk","oml","omn","omo","omp","omq","omr","omt","omu","omv","omw","omx","omy","ona","onb","one","ong","oni","onj","onk","onn","ono","onp","onr","ons","ont","onu","onw","onx","ood","oog","oon","oor","oos","opa","opk","opm","opo","opt","opy","ora","orc","ore","org","orh","orn","oro","orr","ors","ort","oru","orv","orw","orx","ory","orz","osa","osc","osi","osn","oso","osp","ost","osu","osx","ota","otb","otd","ote","oti","otk","otl","otm","otn","oto","otq","otr","ots","ott","otu","otw","otx","oty","otz","oua","oub","oue","oui","oum","oun","ovd","owi","owl","oyb","oyd","oym","oyy","ozm","paa","pab","pac","pad","pae","paf","pag","pah","pai","pak","pal","pam","pao","pap","paq","par","pas","pat","pau","pav","paw","pax","pay","paz","pbb","pbc","pbe","pbf","pbg","pbh","pbi","pbl","pbm","pbn","pbo","pbp","pbr","pbs","pbt","pbu","pbv","pby","pbz","pca","pcb","pcc","pcd","pce","pcf","pcg","pch","pci","pcj","pck","pcl","pcm","pcn","pcp","pcr","pcw","pda","pdc","pdi","pdn","pdo","pdt","pdu","pea","peb","ped","pee","pef","peg","peh","pei","pej","pek","pel","pem","peo","pep","peq","pes","pev","pex","pey","pez","pfa","pfe","pfl","pga","pgd","pgg","pgi","pgk","pgl","pgn","pgs","pgu","pgy","pgz","pha","phd","phg","phh","phi","phj","phk","phl","phm","phn","pho","phq","phr","pht","phu","phv","phw","pia","pib","pic","pid","pie","pif","pig","pih","pii","pij","pil","pim","pin","pio","pip","pir","pis","pit","piu","piv","piw","pix","piy","piz","pjt","pka","pkb","pkc","pkg","pkh","pkn","pko","pkp","pkr","pks","pkt","pku","pla","plb","plc","pld","ple","plf","plg","plh","plj","plk","pll","pln","plo","plp","plq","plr","pls","plt","plu","plv","plw","ply","plz","pma","pmb","pmc","pmd","pme","pmf","pmh","pmi","pmj","pmk","pml","pmm","pmn","pmo","pmq","pmr","pms","pmt","pmu","pmw","pmx","pmy","pmz","pna","pnb","pnc","pnd","pne","png","pnh","pni","pnj","pnk","pnl","pnm","pnn","pno","pnp","pnq","pnr","pns","pnt","pnu","pnv","pnw","pnx","pny","pnz","poc","pod","poe","pof","pog","poh","poi","pok","pom","pon","poo","pop","poq","pos","pot","pov","pow","pox","poy","poz","ppa","ppe","ppi","ppk","ppl","ppm","ppn","ppo","ppp","ppq","ppr","pps","ppt","ppu","pqa","pqe","pqm","pqw","pra","prb","prc","prd","pre","prf","prg","prh","pri","prk","prl","prm","prn","pro","prp","prq","prr","prs","prt","pru","prw","prx","pry","prz","psa","psc","psd","pse","psg","psh","psi","psl","psm","psn","pso","psp","psq","psr","pss","pst","psu","psw","psy","pta","pth","pti","ptn","pto","ptp","ptq","ptr","ptt","ptu","ptv","ptw","pty","pua","pub","puc","pud","pue","puf","pug","pui","puj","puk","pum","puo","pup","puq","pur","put","puu","puw","pux","puy","puz","pwa","pwb","pwg","pwi","pwm","pwn","pwo","pwr","pww","pxm","pye","pym","pyn","pys","pyu","pyx","pyy","pze","pzh","pzn","qaa..qtz","qua","qub","quc","qud","quf","qug","quh","qui","quk","qul","qum","qun","qup","quq","qur","qus","quv","quw","qux","quy","quz","qva","qvc","qve","qvh","qvi","qvj","qvl","qvm","qvn","qvo","qvp","qvs","qvw","qvy","qvz","qwa","qwc","qwe","qwh","qwm","qws","qwt","qxa","qxc","qxh","qxl","qxn","qxo","qxp","qxq","qxr","qxs","qxt","qxu","qxw","qya","qyp","raa","rab","rac","rad","raf","rag","rah","rai","raj","rak","ral","ram","ran","rao","rap","raq","rar","ras","rat","rau","rav","raw","rax","ray","raz","rbb","rbk","rbl","rbp","rcf","rdb","rea","reb","ree","reg","rei","rej","rel","rem","ren","rer","res","ret","rey","rga","rge","rgk","rgn","rgr","rgs","rgu","rhg","rhp","ria","rib","rie","rif","ril","rim","rin","rir","rit","riu","rjg","rji","rjs","rka","rkb","rkh","rki","rkm","rkt","rkw","rma","rmb","rmc","rmd","rme","rmf","rmg","rmh","rmi","rmk","rml","rmm","rmn","rmo","rmp","rmq","rmr","rms","rmt","rmu","rmv","rmw","rmx","rmy","rmz","rna","rnb","rnd","rng","rnl","rnn","rnp","rnr","rnw","roa","rob","roc","rod","roe","rof","rog","rol","rom","roo","rop","ror","rou","row","rpn","rpt","rri","rrm","rro","rrt","rsb","rsi","rsk","rsl","rsm","rsn","rsw","rtc","rth","rtm","rts","rtw","rub","ruc","rue","ruf","rug","ruh","rui","ruk","ruo","rup","ruq","rut","ruu","ruy","ruz","rwa","rwk","rwl","rwm","rwo","rwr","rxd","rxw","ryn","rys","ryu","rzh","saa","sab","sac","sad","sae","saf","sah","sai","saj","sak","sal","sam","sao","sap","saq","sar","sas","sat","sau","sav","saw","sax","say","saz","sba","sbb","sbc","sbd","sbe","sbf","sbg","sbh","sbi","sbj","sbk","sbl","sbm","sbn","sbo","sbp","sbq","sbr","sbs","sbt","sbu","sbv","sbw","sbx","sby","sbz","sca","scb","sce","scf","scg","sch","sci","sck","scl","scn","sco","scp","scq","scs","sct","scu","scv","scw","scx","sda","sdb","sdc","sde","sdf","sdg","sdh","sdj","sdk","sdl","sdm","sdn","sdo","sdp","sdq","sdr","sds","sdt","sdu","sdv","sdx","sdz","sea","seb","sec","sed","see","sef","seg","seh","sei","sej","sek","sel","sem","sen","seo","sep","seq","ser","ses","set","seu","sev","sew","sey","sez","sfb","sfe","sfm","sfs","sfw","sga","sgb","sgc","sgd","sge","sgg","sgh","sgi","sgj","sgk","sgl","sgm","sgn","sgo","sgp","sgr","sgs","sgt","sgu","sgw","sgx","sgy","sgz","sha","shb","shc","shd","she","shg","shh","shi","shj","shk","shl","shm","shn","sho","shp","shq","shr","shs","sht","shu","shv","shw","shx","shy","shz","sia","sib","sid","sie","sif","sig","sih","sii","sij","sik","sil","sim","sio","sip","siq","sir","sis","sit","siu","siv","siw","six","siy","siz","sja","sjb","sjd","sje","sjg","sjk","sjl","sjm","sjn","sjo","sjp","sjr","sjs","sjt","sju","sjw","ska","skb","skc","skd","ske","skf","skg","skh","ski","skj","skk","skm","skn","sko","skp","skq","skr","sks","skt","sku","skv","skw","skx","sky","skz","sla","slc","sld","sle","slf","slg","slh","sli","slj","sll","slm","sln","slp","slq","slr","sls","slt","slu","slw","slx","sly","slz","sma","smb","smc","smd","smf","smg","smh","smi","smj","smk","sml","smm","smn","smp","smq","smr","sms","smt","smu","smv","smw","smx","smy","smz","snb","snc","sne","snf","sng","snh","sni","snj","snk","snl","snm","snn","sno","snp","snq","snr","sns","snu","snv","snw","snx","sny","snz","soa","sob","soc","sod","soe","sog","soh","soi","soj","sok","sol","son","soo","sop","soq","sor","sos","sou","sov","sow","sox","soy","soz","spb","spc","spd","spe","spg","spi","spk","spl","spm","spn","spo","spp","spq","spr","sps","spt","spu","spv","spx","spy","sqa","sqh","sqj","sqk","sqm","sqn","sqo","sqq","sqr","sqs","sqt","squ","sqx","sra","srb","src","sre","srf","srg","srh","sri","srk","srl","srm","srn","sro","srq","srr","srs","srt","sru","srv","srw","srx","sry","srz","ssa","ssb","ssc","ssd","sse","ssf","ssg","ssh","ssi","ssj","ssk","ssl","ssm","ssn","sso","ssp","ssq","ssr","sss","sst","ssu","ssv","ssx","ssy","ssz","sta","stb","std","ste","stf","stg","sth","sti","stj","stk","stl","stm","stn","sto","stp","stq","str","sts","stt","stu","stv","stw","sty","sua","sub","suc","sue","sug","sui","suj","suk","sul","sum","suo","suq","sur","sus","sut","suv","suw","sux","suy","suz","sva","svb","svc","sve","svk","svm","svr","svs","svx","swb","swc","swf","swg","swh","swi","swj","swk","swl","swm","swn","swo","swp","swq","swr","sws","swt","swu","swv","sww","swx","swy","sxb","sxc","sxe","sxg","sxk","sxl","sxm","sxn","sxo","sxr","sxs","sxu","sxw","sya","syb","syc","syd","syi","syk","syl","sym","syn","syo","syr","sys","syw","syx","syy","sza","szb","szc","szd","sze","szg","szl","szn","szp","szs","szv","szw","szy","taa","tab","tac","tad","tae","taf","tag","tai","taj","tak","tal","tan","tao","tap","taq","tar","tas","tau","tav","taw","tax","tay","taz","tba","tbb","tbc","tbd","tbe","tbf","tbg","tbh","tbi","tbj","tbk","tbl","tbm","tbn","tbo","tbp","tbq","tbr","tbs","tbt","tbu","tbv","tbw","tbx","tby","tbz","tca","tcb","tcc","tcd","tce","tcf","tcg","tch","tci","tck","tcl","tcm","tcn","tco","tcp","tcq","tcs","tct","tcu","tcw","tcx","tcy","tcz","tda","tdb","tdc","tdd","tde","tdf","tdg","tdh","tdi","tdj","tdk","tdl","tdm","tdn","tdo","tdq","tdr","tds","tdt","tdu","tdv","tdx","tdy","tea","teb","tec","ted","tee","tef","teg","teh","tei","tek","tem","ten","teo","tep","teq","ter","tes","tet","teu","tev","tew","tex","tey","tez","tfi","tfn","tfo","tfr","tft","tga","tgb","tgc","tgd","tge","tgf","tgg","tgh","tgi","tgj","tgn","tgo","tgp","tgq","tgr","tgs","tgt","tgu","tgv","tgw","tgx","tgy","tgz","thc","thd","the","thf","thh","thi","thk","thl","thm","thn","thp","thq","thr","ths","tht","thu","thv","thw","thx","thy","thz","tia","tic","tid","tie","tif","tig","tih","tii","tij","tik","til","tim","tin","tio","tip","tiq","tis","tit","tiu","tiv","tiw","tix","tiy","tiz","tja","tjg","tji","tjj","tjl","tjm","tjn","tjo","tjp","tjs","tju","tjw","tka","tkb","tkd","tke","tkf","tkg","tkk","tkl","tkm","tkn","tkp","tkq","tkr","tks","tkt","tku","tkv","tkw","tkx","tkz","tla","tlb","tlc","tld","tlf","tlg","tlh","tli","tlj","tlk","tll","tlm","tln","tlo","tlp","tlq","tlr","tls","tlt","tlu","tlv","tlw","tlx","tly","tma","tmb","tmc","tmd","tme","tmf","tmg","tmh","tmi","tmj","tmk","tml","tmm","tmn","tmo","tmp","tmq","tmr","tms","tmt","tmu","tmv","tmw","tmy","tmz","tna","tnb","tnc","tnd","tne","tnf","tng","tnh","tni","tnk","tnl","tnm","tnn","tno","tnp","tnq","tnr","tns","tnt","tnu","tnv","tnw","tnx","tny","tnz","tob","toc","tod","toe","tof","tog","toh","toi","toj","tok","tol","tom","too","top","toq","tor","tos","tou","tov","tow","tox","toy","toz","tpa","tpc","tpe","tpf","tpg","tpi","tpj","tpk","tpl","tpm","tpn","tpo","tpp","tpq","tpr","tpt","tpu","tpv","tpw","tpx","tpy","tpz","tqb","tql","tqm","tqn","tqo","tqp","tqq","tqr","tqt","tqu","tqw","tra","trb","trc","trd","tre","trf","trg","trh","tri","trj","trk","trl","trm","trn","tro","trp","trq","trr","trs","trt","tru","trv","trw","trx","try","trz","tsa","tsb","tsc","tsd","tse","tsf","tsg","tsh","tsi","tsj","tsk","tsl","tsm","tsp","tsq","tsr","tss","tst","tsu","tsv","tsw","tsx","tsy","tsz","tta","ttb","ttc","ttd","tte","ttf","ttg","tth","tti","ttj","ttk","ttl","ttm","ttn","tto","ttp","ttq","ttr","tts","ttt","ttu","ttv","ttw","tty","ttz","tua","tub","tuc","tud","tue","tuf","tug","tuh","tui","tuj","tul","tum","tun","tuo","tup","tuq","tus","tut","tuu","tuv","tuw","tux","tuy","tuz","tva","tvd","tve","tvi","tvk","tvl","tvm","tvn","tvo","tvs","tvt","tvu","tvw","tvx","tvy","twa","twb","twc","twd","twe","twf","twg","twh","twl","twm","twn","two","twp","twq","twr","twt","twu","tww","twx","twy","txa","txb","txc","txe","txg","txh","txi","txj","txm","txn","txo","txq","txr","txs","txt","txu","txx","txy","tya","tye","tyh","tyi","tyj","tyl","tyn","typ","tyr","tys","tyt","tyu","tyv","tyx","tyy","tyz","tza","tzh","tzj","tzl","tzm","tzn","tzo","tzx","uam","uan","uar","uba","ubi","ubl","ubr","ubu","uby","uda","ude","udg","udi","udj","udl","udm","udu","ues","ufi","uga","ugb","uge","ugh","ugn","ugo","ugy","uha","uhn","uis","uiv","uji","uka","ukg","ukh","uki","ukk","ukl","ukp","ukq","uks","uku","ukv","ukw","uky","ula","ulb","ulc","ule","ulf","uli","ulk","ull","ulm","uln","ulu","ulw","uly","uma","umb","umc","umd","umg","umi","umm","umn","umo","ump","umr","ums","umu","una","und","une","ung","uni","unk","unm","unn","unp","unr","unu","unx","unz","uok","uon","upi","upv","ura","urb","urc","ure","urf","urg","urh","uri","urj","urk","url","urm","urn","uro","urp","urr","urt","uru","urv","urw","urx","ury","urz","usa","ush","usi","usk","usp","uss","usu","uta","ute","uth","utp","utr","utu","uum","uun","uur","uuu","uve","uvh","uvl","uwa","uya","uzn","uzs","vaa","vae","vaf","vag","vah","vai","vaj","val","vam","van","vao","vap","var","vas","vau","vav","vay","vbb","vbk","vec","ved","vel","vem","veo","vep","ver","vgr","vgt","vic","vid","vif","vig","vil","vin","vis","vit","viv","vjk","vka","vki","vkj","vkk","vkl","vkm","vkn","vko","vkp","vkt","vku","vkz","vlp","vls","vma","vmb","vmc","vmd","vme","vmf","vmg","vmh","vmi","vmj","vmk","vml","vmm","vmp","vmq","vmr","vms","vmu","vmv","vmw","vmx","vmy","vmz","vnk","vnm","vnp","vor","vot","vra","vro","vrs","vrt","vsi","vsl","vsn","vsv","vto","vum","vun","vut","vwa","waa","wab","wac","wad","wae","waf","wag","wah","wai","waj","wak","wal","wam","wan","wao","wap","waq","war","was","wat","wau","wav","waw","wax","way","waz","wba","wbb","wbe","wbf","wbh","wbi","wbj","wbk","wbl","wbm","wbp","wbq","wbr","wbs","wbt","wbv","wbw","wca","wci","wdd","wdg","wdj","wdk","wdt","wdu","wdy","wea","wec","wed","weg","weh","wei","wem","wen","weo","wep","wer","wes","wet","weu","wew","wfg","wga","wgb","wgg","wgi","wgo","wgu","wgw","wgy","wha","whg","whk","whu","wib","wic","wie","wif","wig","wih","wii","wij","wik","wil","wim","win","wir","wit","wiu","wiv","wiw","wiy","wja","wji","wka","wkb","wkd","wkl","wkr","wku","wkw","wky","wla","wlc","wle","wlg","wlh","wli","wlk","wll","wlm","wlo","wlr","wls","wlu","wlv","wlw","wlx","wly","wma","wmb","wmc","wmd","wme","wmg","wmh","wmi","wmm","wmn","wmo","wms","wmt","wmw","wmx","wnb","wnc","wnd","wne","wng","wni","wnk","wnm","wnn","wno","wnp","wnu","wnw","wny","woa","wob","woc","wod","woe","wof","wog","woi","wok","wom","won","woo","wor","wos","wow","woy","wpc","wra","wrb","wrd","wrg","wrh","wri","wrk","wrl","wrm","wrn","wro","wrp","wrr","wrs","wru","wrv","wrw","wrx","wry","wrz","wsa","wsg","wsi","wsk","wsr","wss","wsu","wsv","wtb","wtf","wth","wti","wtk","wtm","wtw","wua","wub","wud","wuh","wul","wum","wun","wur","wut","wuu","wuv","wux","wuy","wwa","wwb","wwo","wwr","www","wxa","wxw","wya","wyb","wyi","wym","wyn","wyr","wyy","xaa","xab","xac","xad","xae","xag","xai","xaj","xak","xal","xam","xan","xao","xap","xaq","xar","xas","xat","xau","xav","xaw","xay","xba","xbb","xbc","xbd","xbe","xbg","xbi","xbj","xbm","xbn","xbo","xbp","xbr","xbw","xbx","xby","xcb","xcc","xce","xcg","xch","xcl","xcm","xcn","xco","xcr","xct","xcu","xcv","xcw","xcy","xda","xdc","xdk","xdm","xdo","xdq","xdy","xeb","xed","xeg","xel","xem","xep","xer","xes","xet","xeu","xfa","xga","xgb","xgd","xgf","xgg","xgi","xgl","xgm","xgn","xgr","xgu","xgw","xha","xhc","xhd","xhe","xhm","xhr","xht","xhu","xhv","xia","xib","xii","xil","xin","xip","xir","xis","xiv","xiy","xjb","xjt","xka","xkb","xkc","xkd","xke","xkf","xkg","xkh","xki","xkj","xkk","xkl","xkn","xko","xkp","xkq","xkr","xks","xkt","xku","xkv","xkw","xkx","xky","xkz","xla","xlb","xlc","xld","xle","xlg","xli","xln","xlo","xlp","xls","xlu","xly","xma","xmb","xmc","xmd","xme","xmf","xmg","xmh","xmj","xmk","xml","xmm","xmn","xmo","xmp","xmq","xmr","xms","xmt","xmu","xmv","xmw","xmx","xmy","xmz","xna","xnb","xnd","xng","xnh","xni","xnj","xnk","xnm","xnn","xno","xnq","xnr","xns","xnt","xnu","xny","xnz","xoc","xod","xog","xoi","xok","xom","xon","xoo","xop","xor","xow","xpa","xpb","xpc","xpd","xpe","xpf","xpg","xph","xpi","xpj","xpk","xpl","xpm","xpn","xpo","xpp","xpq","xpr","xps","xpt","xpu","xpv","xpw","xpx","xpy","xpz","xqa","xqt","xra","xrb","xrd","xre","xrg","xri","xrm","xrn","xrq","xrr","xrt","xru","xrw","xsa","xsb","xsc","xsd","xse","xsh","xsi","xsj","xsl","xsm","xsn","xso","xsp","xsq","xsr","xss","xsu","xsv","xsy","xta","xtb","xtc","xtd","xte","xtg","xth","xti","xtj","xtl","xtm","xtn","xto","xtp","xtq","xtr","xts","xtt","xtu","xtv","xtw","xty","xtz","xua","xub","xud","xug","xuj","xul","xum","xun","xuo","xup","xur","xut","xuu","xve","xvi","xvn","xvo","xvs","xwa","xwc","xwd","xwe","xwg","xwj","xwk","xwl","xwo","xwr","xwt","xww","xxb","xxk","xxm","xxr","xxt","xya","xyb","xyj","xyk","xyl","xyt","xyy","xzh","xzm","xzp","yaa","yab","yac","yad","yae","yaf","yag","yah","yai","yaj","yak","yal","yam","yan","yao","yap","yaq","yar","yas","yat","yau","yav","yaw","yax","yay","yaz","yba","ybb","ybd","ybe","ybh","ybi","ybj","ybk","ybl","ybm","ybn","ybo","ybx","yby","ych","ycl","ycn","ycp","ycr","yda","ydd","yde","ydg","ydk","yds","yea","yec","yee","yei","yej","yel","yen","yer","yes","yet","yeu","yev","yey","yga","ygi","ygl","ygm","ygp","ygr","ygs","ygu","ygw","yha","yhd","yhl","yhs","yia","yif","yig","yih","yii","yij","yik","yil","yim","yin","yip","yiq","yir","yis","yit","yiu","yiv","yix","yiy","yiz","yka","ykg","ykh","yki","ykk","ykl","ykm","ykn","yko","ykr","ykt","yku","yky","yla","ylb","yle","ylg","yli","yll","ylm","yln","ylo","ylr","ylu","yly","yma","ymb","ymc","ymd","yme","ymg","ymh","ymi","ymk","yml","ymm","ymn","ymo","ymp","ymq","ymr","yms","ymt","ymx","ymz","yna","ynd","yne","yng","ynh","ynk","ynl","ynn","yno","ynq","yns","ynu","yob","yog","yoi","yok","yol","yom","yon","yos","yot","yox","yoy","ypa","ypb","ypg","yph","ypk","ypm","ypn","ypo","ypp","ypz","yra","yrb","yre","yri","yrk","yrl","yrm","yrn","yro","yrs","yrw","yry","ysc","ysd","ysg","ysl","ysm","ysn","yso","ysp","ysr","yss","ysy","yta","ytl","ytp","ytw","yty","yua","yub","yuc","yud","yue","yuf","yug","yui","yuj","yuk","yul","yum","yun","yup","yuq","yur","yut","yuu","yuw","yux","yuy","yuz","yva","yvt","ywa","ywg","ywl","ywn","ywq","ywr","ywt","ywu","yww","yxa","yxg","yxl","yxm","yxu","yxy","yyr","yyu","yyz","yzg","yzk","zaa","zab","zac","zad","zae","zaf","zag","zah","zai","zaj","zak","zal","zam","zao","zap","zaq","zar","zas","zat","zau","zav","zaw","zax","zay","zaz","zba","zbc","zbe","zbl","zbt","zbu","zbw","zca","zcd","zch","zdj","zea","zeg","zeh","zem","zen","zga","zgb","zgh","zgm","zgn","zgr","zhb","zhd","zhi","zhn","zhw","zhx","zia","zib","zik","zil","zim","zin","zir","ziw","ziz","zka","zkb","zkd","zkg","zkh","zkk","zkn","zko","zkp","zkr","zkt","zku","zkv","zkz","zla","zle","zlj","zlm","zln","zlq","zls","zlu","zlw","zma","zmb","zmc","zmd","zme","zmf","zmg","zmh","zmi","zmj","zmk","zml","zmm","zmn","zmo","zmp","zmq","zmr","zms","zmt","zmu","zmv","zmw","zmx","zmy","zmz","zna","znd","zne","zng","znk","zns","zoc","zoh","zom","zoo","zoq","zor","zos","zpa","zpb","zpc","zpd","zpe","zpf","zpg","zph","zpi","zpj","zpk","zpl","zpm","zpn","zpo","zpp","zpq","zpr","zps","zpt","zpu","zpv","zpw","zpx","zpy","zpz","zqe","zra","zrg","zrn","zro","zrp","zrs","zsa","zsk","zsl","zsm","zsr","zsu","zte","ztg","ztl","ztm","ztn","ztp","ztq","zts","ztt","ztu","ztx","zty","zua","zuh","zum","zun","zuy","zwa","zxx","zyb","zyg","zyj","zyn","zyp","zza"]
@@ -1,45 +0,0 @@
1
- const assert = require('assert');
2
- const { describe, it } = require('node:test')
3
- const buildRoot = require('../lib/build-root');
4
- const { Root, cacheDoc } = require('als-document');
5
-
6
- describe('Basic tests', function () {
7
- it('should create an instance of Root if undefind', () => {
8
- assert(buildRoot() instanceof Root)
9
- });
10
-
11
- it('should create an instance of Root from cached', () => {
12
- const cached = cacheDoc(new Root())
13
- assert(buildRoot(cached) instanceof Root)
14
- });
15
-
16
- it('should create an instance of Root from ready root', () => {
17
- const root = new Root()
18
- assert(buildRoot(root) !== root)
19
- });
20
-
21
- it('should add !DOCTYPE', () => {
22
- const root = buildRoot()
23
- assert(root.childNodes[0].tagName === '!DOCTYPE')
24
- });
25
-
26
- it('should create an instance of Root from HTML string', () => {
27
- const htmlString = '<html><head><title>Test</title></head><body></body></html>';
28
- const root = buildRoot(htmlString);
29
- assert(root instanceof Root);
30
- assert.strictEqual(root.childNodes.length > 0, true);
31
- assert.strictEqual(root.childNodes[0].tagName, '!DOCTYPE');
32
- });
33
-
34
- it('should create an instance of Root from object', () => {
35
- const docObject = cacheDoc('<html></html>')
36
- const root = buildRoot(docObject);
37
- assert(root instanceof Root);
38
- });
39
-
40
- it('should create an empty Root if object does not have tagName', () => {
41
- const root = buildRoot({});
42
- assert(root instanceof Root);
43
- });
44
- })
45
-