@vyr/engine 0.0.32 → 0.0.34

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.
Files changed (137) hide show
  1. package/package.json +6 -3
  2. package/src/ArrayUtils.ts +63 -65
  3. package/src/AsyncTask.ts +67 -71
  4. package/src/Category.ts +69 -86
  5. package/src/Color.ts +3 -111
  6. package/src/Engine.ts +12 -24
  7. package/src/Executor.ts +109 -0
  8. package/src/Generate.ts +23 -40
  9. package/src/InputSystem.ts +106 -108
  10. package/src/Listener.ts +58 -59
  11. package/src/ObjectPool.ts +83 -84
  12. package/src/ObjectUtils.ts +97 -49
  13. package/src/Scriptable.ts +82 -0
  14. package/src/Serialization.ts +4 -6
  15. package/src/Traverser.ts +41 -39
  16. package/src/actor/Actor.ts +23 -27
  17. package/src/actor/AnimationUnitActor.ts +22 -36
  18. package/src/actor/DivActor.ts +21 -41
  19. package/src/actor/FragmentActor.ts +1 -5
  20. package/src/actor/HTMLActor.ts +81 -0
  21. package/src/actor/HTMLServiceActor.ts +49 -0
  22. package/src/actor/{HTMTransformControllerActor.ts → HTMLTransformControllerActor.ts} +178 -71
  23. package/src/actor/InputActor.ts +50 -0
  24. package/src/actor/TextActor.ts +51 -0
  25. package/src/actor/index.ts +6 -5
  26. package/src/asset/Asset.ts +23 -68
  27. package/src/asset/AssetGraph.ts +21 -28
  28. package/src/descriptor/AnimationUnit.ts +81 -0
  29. package/src/descriptor/Camera.ts +12 -0
  30. package/src/descriptor/Controller.ts +6 -0
  31. package/src/descriptor/Descriptor.ts +133 -113
  32. package/src/descriptor/Div.ts +29 -0
  33. package/src/descriptor/HTML.ts +22 -0
  34. package/src/descriptor/HTMLService.ts +42 -0
  35. package/src/descriptor/HTMLTransformController.ts +67 -0
  36. package/src/descriptor/Input.ts +29 -0
  37. package/src/descriptor/Interaction.ts +80 -0
  38. package/src/descriptor/Node.ts +98 -0
  39. package/src/descriptor/Scene.ts +110 -0
  40. package/src/descriptor/Service.ts +11 -0
  41. package/src/descriptor/Store.ts +136 -0
  42. package/src/descriptor/Text.ts +36 -0
  43. package/src/descriptor/index.ts +14 -15
  44. package/src/graphics/Collection.ts +1 -5
  45. package/src/graphics/Compilation.ts +15 -19
  46. package/src/graphics/Graphics.ts +41 -54
  47. package/src/graphics/Observer.ts +6 -14
  48. package/src/graphics/Unit.ts +3 -9
  49. package/src/graphics/VariableProxy.ts +11 -15
  50. package/src/index.ts +5 -5
  51. package/src/interpreter/AnimationUnitInterpreter.ts +7 -9
  52. package/src/interpreter/DivInterpreter.ts +10 -13
  53. package/src/interpreter/FragmentInterpreter.ts +2 -6
  54. package/src/interpreter/HTMLServiceInterpreter.ts +25 -15
  55. package/src/interpreter/HTMLTransformControllerInterpreter.ts +9 -12
  56. package/src/interpreter/InputInterpreter.ts +41 -0
  57. package/src/interpreter/Interpreter.ts +3 -4
  58. package/src/interpreter/SceneInterpreter.ts +93 -0
  59. package/src/interpreter/ServiceInterpreter.ts +8 -15
  60. package/src/interpreter/StoreInterpreter.ts +7 -0
  61. package/src/interpreter/TextInterpreter.ts +41 -0
  62. package/src/interpreter/index.ts +5 -7
  63. package/src/locale/Language.ts +1 -5
  64. package/src/locale/LanguageProvider.ts +164 -21
  65. package/src/math/Euler.ts +2 -5
  66. package/src/math/Matrix4.ts +2 -4
  67. package/src/math/Quaternion.ts +2 -4
  68. package/src/math/Vector2.ts +4 -4
  69. package/src/math/Vector3.ts +2 -4
  70. package/src/math/utils.ts +1 -5
  71. package/src/schema/AnimationUnit.ts +68 -0
  72. package/src/schema/Asset.ts +13 -0
  73. package/src/schema/Descriptor.ts +41 -0
  74. package/src/schema/HTML.ts +261 -0
  75. package/src/schema/Interaction.ts +50 -0
  76. package/src/schema/Scene.ts +138 -0
  77. package/src/schema/Store.ts +8 -0
  78. package/src/schema/index.ts +7 -0
  79. package/src/scripts/ConditionScriptable.ts +196 -0
  80. package/src/scripts/FetchScriptable.ts +51 -0
  81. package/src/scripts/FindScriptable.ts +23 -0
  82. package/src/scripts/InvokeScriptable.ts +13 -0
  83. package/src/scripts/SwitchSceneScriptable.ts +18 -0
  84. package/src/scripts/UpdateScriptable.ts +60 -0
  85. package/src/scripts/index.ts +6 -0
  86. package/src/utils/AssetProvider.ts +4 -77
  87. package/src/utils/DOM.ts +37 -0
  88. package/src/utils/HTML.ts +5 -0
  89. package/src/utils/Service.ts +40 -0
  90. package/src/utils/constants.ts +1 -5
  91. package/src/utils/http.ts +2 -21
  92. package/src/utils/index.ts +3 -1
  93. package/src/actor/HTMActor.ts +0 -169
  94. package/src/actor/HTMServiceActor.ts +0 -57
  95. package/src/actor/StyleActor.ts +0 -96
  96. package/src/descriptor/AnimationUnitDescriptor.ts +0 -65
  97. package/src/descriptor/CameraDescriptor.ts +0 -12
  98. package/src/descriptor/ControllerDescriptor.ts +0 -16
  99. package/src/descriptor/DatasetDescriptor.ts +0 -90
  100. package/src/descriptor/DivDescriptor.ts +0 -18
  101. package/src/descriptor/DynamicDescriptor.ts +0 -27
  102. package/src/descriptor/HTMLDescriptor.ts +0 -87
  103. package/src/descriptor/HTMLServiceDescriptor.ts +0 -19
  104. package/src/descriptor/HTMLTransformControllerDescriptor.ts +0 -34
  105. package/src/descriptor/NodeDescriptor.ts +0 -32
  106. package/src/descriptor/PrefabDescriptor.ts +0 -53
  107. package/src/descriptor/PrefabInstanceDescriptor.ts +0 -32
  108. package/src/descriptor/ServiceDescriptor.ts +0 -32
  109. package/src/descriptor/ServiceSchedulerDescriptor.ts +0 -32
  110. package/src/descriptor/StyleDescriptor.ts +0 -213
  111. package/src/interaction/InteractionDescriptor.ts +0 -96
  112. package/src/interaction/InteractionExecutor.ts +0 -84
  113. package/src/interaction/Scriptable.ts +0 -44
  114. package/src/interaction/index.ts +0 -3
  115. package/src/interpreter/DatasetInterpreter.ts +0 -11
  116. package/src/interpreter/DynamicInterpreter.ts +0 -207
  117. package/src/interpreter/PrefaInterpreter.ts +0 -11
  118. package/src/interpreter/PrefabInstanceInterpreter.ts +0 -12
  119. package/src/interpreter/ServiceSchedulerInterpreter.ts +0 -42
  120. package/src/interpreter/StyleInterpreter.ts +0 -66
  121. package/src/preset/execute/dataset/index.ts +0 -1
  122. package/src/preset/execute/dataset/update.ts +0 -51
  123. package/src/preset/execute/graphics/index.ts +0 -1
  124. package/src/preset/execute/graphics/invoke.ts +0 -48
  125. package/src/preset/execute/index.ts +0 -4
  126. package/src/preset/execute/net/http.ts +0 -52
  127. package/src/preset/execute/net/index.ts +0 -1
  128. package/src/preset/execute/scheduler/index.ts +0 -1
  129. package/src/preset/execute/scheduler/switch.ts +0 -46
  130. package/src/preset/index.ts +0 -7
  131. package/src/preset/interaction/graphics/index.ts +0 -1
  132. package/src/preset/interaction/graphics/invoke.ts +0 -27
  133. package/src/preset/interaction/index.ts +0 -2
  134. package/src/preset/interaction/scheduler/index.ts +0 -1
  135. package/src/preset/interaction/scheduler/switch.ts +0 -27
  136. package/src/setup/index.ts +0 -17
  137. package/src/utils/compile.ts +0 -50
@@ -1,13 +1,13 @@
1
1
  import { Euler, Quaternion, Vector2, Vector3 } from "../math"
2
- import { AnimationUnitDescriptor, Descriptor } from "../descriptor"
2
+ import { AnimationUnit, Descriptor } from "../descriptor"
3
3
  import { AnimationUnitInterpreter } from "../interpreter"
4
4
  import { Graphics, TickArgs } from "../graphics"
5
5
  import { ObjectUtils } from '../ObjectUtils'
6
6
  import { Color } from '../Color'
7
7
  import { Actor } from "./Actor"
8
8
 
9
- abstract class AnimationUnitActor extends Actor {
10
- static parse(descriptor: AnimationUnitDescriptor) {
9
+ export abstract class AnimationUnitActor extends Actor {
10
+ static parse(descriptor: AnimationUnit) {
11
11
  switch (descriptor.frameData.type) {
12
12
  case 'number':
13
13
  return new NumberAnimationUnitargetActor(descriptor, descriptor.frameData.startValue, descriptor.frameData.endValue)
@@ -28,22 +28,20 @@ abstract class AnimationUnitActor extends Actor {
28
28
  startTime: number
29
29
  duration: number
30
30
  mode: number
31
- path: string
32
- keys: string[]
31
+ propertyPath: string
33
32
  count: number
34
33
  uptime: number
35
34
  unlisten!: () => void
36
35
  target!: Descriptor
37
36
  rawValue!: any
38
37
 
39
- constructor(descriptor: AnimationUnitDescriptor) {
38
+ constructor(descriptor: AnimationUnit) {
40
39
  super()
41
40
  this.play = descriptor.play
42
41
  this.startTime = descriptor.startTime
43
42
  this.duration = descriptor.duration
44
43
  this.mode = descriptor.mode
45
- this.path = descriptor.path
46
- this.keys = ObjectUtils.parseKey(descriptor.path)
44
+ this.propertyPath = descriptor.propertyPath
47
45
  this.count = descriptor.count
48
46
  this.uptime = 0
49
47
  }
@@ -59,10 +57,10 @@ abstract class AnimationUnitActor extends Actor {
59
57
  setTarget(descriptor: Descriptor) {
60
58
  this.target = descriptor
61
59
  let rawValue = descriptor as any
62
- for (const key of this.keys) {
63
- rawValue = rawValue[key]
64
- if (rawValue === undefined) return
65
- }
60
+ ObjectUtils.nextByPropertyPath(descriptor, this.propertyPath, (property, key) => {
61
+ rawValue = property[key]
62
+ })
63
+ if (rawValue === undefined) return
66
64
  this.rawValue = Descriptor.deepClone(rawValue)
67
65
  }
68
66
 
@@ -76,19 +74,10 @@ abstract class AnimationUnitActor extends Actor {
76
74
  abstract setValue(radio: number): void
77
75
 
78
76
  traverseWithTailCallback(set: (target: any, key: string) => void) {
79
- let target: { [k: string]: any } = this.target
80
- const count = this.keys.length - 1
81
- for (let i = 0; i <= count; i++) {
82
- if (i === count) {
83
- const key = this.keys[i]
84
- if (target[key] === undefined) return
85
- set(target, key)
86
- this.target.setNeedsUpdate()
87
- } else {
88
- target = target[this.keys[i]]
89
- if (!target) return
90
- }
91
- }
77
+ ObjectUtils.nextByPropertyPath(this.target, this.propertyPath, (property, key) => {
78
+ set(property, key)
79
+ this.target.setNeedsUpdate()
80
+ })
92
81
  }
93
82
 
94
83
  update = (args: TickArgs) => {
@@ -137,7 +126,7 @@ class NumberAnimationUnitargetActor extends AnimationUnitActor {
137
126
  startValue
138
127
  distance
139
128
 
140
- constructor(descriptor: AnimationUnitDescriptor, startValue: number, endValue: number) {
129
+ constructor(descriptor: AnimationUnit, startValue: number, endValue: number) {
141
130
  super(descriptor)
142
131
  this.startValue = startValue
143
132
  this.distance = endValue - startValue
@@ -161,7 +150,7 @@ class Vector2AnimationUnitargetActor extends AnimationUnitActor {
161
150
  }
162
151
  startValue: Vector2
163
152
  endValue: Vector2
164
- constructor(descriptor: AnimationUnitDescriptor, startValue: Vector2, endValue: Vector2) {
153
+ constructor(descriptor: AnimationUnit, startValue: Vector2, endValue: Vector2) {
165
154
  super(descriptor)
166
155
  this.startValue = startValue
167
156
  this.endValue = endValue
@@ -186,7 +175,7 @@ class Vector3AnimationUnitargetActor extends AnimationUnitActor {
186
175
  }
187
176
  declare startValue: Vector3
188
177
  declare endValue: Vector3
189
- constructor(descriptor: AnimationUnitDescriptor, startValue: Vector3, endValue: Vector3) {
178
+ constructor(descriptor: AnimationUnit, startValue: Vector3, endValue: Vector3) {
190
179
  super(descriptor)
191
180
  this.startValue = startValue
192
181
  this.endValue = endValue
@@ -225,7 +214,7 @@ class EulerAnimationUnitargetActor extends AnimationUnitActor {
225
214
  }
226
215
  declare startValue: Euler
227
216
  declare endValue: Euler
228
- constructor(descriptor: AnimationUnitDescriptor, startValue: Euler, endValue: Euler) {
217
+ constructor(descriptor: AnimationUnit, startValue: Euler, endValue: Euler) {
229
218
  super(descriptor)
230
219
  this.startValue = startValue
231
220
  this.endValue = endValue
@@ -245,9 +234,9 @@ class EulerAnimationUnitargetActor extends AnimationUnitActor {
245
234
  }
246
235
 
247
236
  class BooleanAnimationUnitargetActor extends AnimationUnitActor {
248
- declare startValue: number
249
- declare endValue: number
250
- constructor(descriptor: AnimationUnitDescriptor, startValue: number, endValue: number) {
237
+ declare startValue: boolean
238
+ declare endValue: boolean
239
+ constructor(descriptor: AnimationUnit, startValue: boolean, endValue: boolean) {
251
240
  super(descriptor)
252
241
  this.startValue = startValue
253
242
  this.endValue = endValue
@@ -271,7 +260,7 @@ class BooleanAnimationUnitargetActor extends AnimationUnitActor {
271
260
  class ColorAnimationUnitargetActor extends AnimationUnitActor {
272
261
  declare startValue: Color
273
262
  declare endValue: Color
274
- constructor(descriptor: AnimationUnitDescriptor, startValue: Color, endValue: Color) {
263
+ constructor(descriptor: AnimationUnit, startValue: Color, endValue: Color) {
275
264
  super(descriptor)
276
265
  this.startValue = startValue
277
266
  this.endValue = endValue
@@ -284,6 +273,3 @@ class ColorAnimationUnitargetActor extends AnimationUnitActor {
284
273
  }
285
274
  }
286
275
 
287
- export {
288
- AnimationUnitActor
289
- }
@@ -1,33 +1,21 @@
1
- import { DivDescriptor, StyleDescriptor } from "../descriptor"
1
+ import { createHTMLDOM } from "../utils"
2
+ import { Div } from "../descriptor"
2
3
  import { Actor } from "./Actor"
3
- import { HTMLActor } from "./HTMActor"
4
+ import { HTMLActor } from "./HTMLActor"
4
5
 
5
- class DivActor extends HTMLActor {
6
- private _text: Text | null = null
7
- get text() {
8
- if (this._text === null) {
9
- this._text = document.createTextNode('')
10
- }
11
- return this._text
12
- }
6
+ export class DivActor extends HTMLActor {
13
7
  private _wrapper: HTMLElement | null = null
14
- readonly DOM
15
8
 
16
9
  constructor(uuid: string) {
17
10
  super(uuid)
18
- this.DOM = this.createDOM()
19
- const wrapper = this.getWrapper()
20
- wrapper.appendChild(this.DOM)
21
11
  }
22
12
 
23
13
  protected createWrapper() {
24
- const wrapper = document.createElement('div')
25
- wrapper.setAttribute('class', HTMLActor.className)
26
- wrapper.setAttribute(HTMLActor.uuidKey, this.uuid)
27
- return wrapper
14
+ const DOM = createHTMLDOM(this.uuid)
15
+ return DOM
28
16
  }
29
17
 
30
- getWrapper() {
18
+ getDOM() {
31
19
  if (this._wrapper === null) {
32
20
  this._wrapper = this.createWrapper()
33
21
  }
@@ -37,34 +25,26 @@ class DivActor extends HTMLActor {
37
25
 
38
26
  add(actor: Actor) {
39
27
  if (actor instanceof HTMLActor) {
40
- const wrapper = actor.getWrapper()
41
- if (wrapper === null) return
42
- if (this.DOM.contains(wrapper)) return
43
- this.DOM.appendChild(wrapper)
28
+ const child = actor.getDOM()
29
+ if (child === null) return
30
+ const DOM = this.getDOM()
31
+ if (DOM.contains(child)) return
32
+ DOM.appendChild(child)
44
33
  }
45
34
  }
46
35
 
47
36
  remove(actor: Actor) {
48
37
  if (actor instanceof HTMLActor) {
49
- const wrapper = actor.getWrapper()
50
- if (wrapper === null) return
51
- if (this.DOM.contains(wrapper)) this.DOM.removeChild(wrapper)
38
+ const child = actor.getDOM()
39
+ if (child === null) return
40
+ const DOM = this.getDOM()
41
+ if (DOM.contains(child)) DOM.removeChild(child)
52
42
  }
53
43
  }
54
44
 
55
- update(descriptor: DivDescriptor) {
56
- const wrapper = this.getWrapper()
57
- const style = this.getWrapperStyle(descriptor)
58
- this.setHTMLStyle(wrapper, style)
59
- this.setHTMLInteraction(wrapper, descriptor)
60
- this.setHTMLStyle(this.DOM, this.getLayoutStyle(descriptor))
61
- const styleClass = [...this.getStyleClass(descriptor)]
62
- if (descriptor.active) styleClass.push(StyleDescriptor.activeName)
63
- this.setStyleClass(this.DOM, styleClass)
64
- this.DOM.style.backgroundImage = descriptor.backroundIamge ? `url(${descriptor.backroundIamge})` : ''
65
- this.text.textContent = descriptor.text
66
- if (this.DOM.contains(this.text) === false) this.DOM.appendChild(this.text)
45
+ update(descriptor: Div) {
46
+ const DOM = this.getDOM()
47
+ this.setHtmlAttributes(DOM, descriptor)
48
+ this.setHTMLInteraction(DOM, descriptor)
67
49
  }
68
- }
69
-
70
- export { DivActor }
50
+ }
@@ -2,7 +2,7 @@ import { Descriptor } from "../descriptor";
2
2
  import { ArrayUtils } from "../ArrayUtils";
3
3
  import { Actor } from "./Actor";
4
4
 
5
- class FragmentActor extends Actor {
5
+ export class FragmentActor extends Actor {
6
6
  private _parent = ''
7
7
  collection: Actor[] = []
8
8
 
@@ -49,8 +49,4 @@ class FragmentActor extends Actor {
49
49
  }
50
50
  ArrayUtils.remove(this.collection, actor)
51
51
  }
52
- }
53
-
54
- export {
55
- FragmentActor
56
52
  }
@@ -0,0 +1,81 @@
1
+ import camelcaseKeys from 'camelcase-keys'
2
+ import { HtmlAttributes, HTMLStyle } from '../schema'
3
+ import { Descriptor, Interaction, HTML } from "../descriptor"
4
+ import { Asset } from "../asset"
5
+ import { Actor } from "./Actor"
6
+
7
+ export abstract class HTMLActor extends Actor {
8
+ static className = 'vyr-html'
9
+ static uuidKey = 'data-vyr-uuid'
10
+ static isTrigger(target: any, uuid: string): target is HTMLElement {
11
+ return target.getAttribute(HTMLActor.uuidKey) === uuid
12
+ }
13
+ private classNames: string[] = []
14
+ readonly uuid
15
+ readonly unlisteners: Array<() => void> = []
16
+
17
+ constructor(uuid: string) {
18
+ super()
19
+ this.uuid = uuid
20
+ }
21
+
22
+ setClassNames(DOM: HTMLElement, classNames: string[]) {
23
+ this.cleanClassNames(DOM)
24
+ this.classNames.push(...classNames)
25
+ DOM.classList.add(...classNames)
26
+ }
27
+
28
+ cleanClassNames(DOM: HTMLElement) {
29
+ if (this.classNames.length === 0) return
30
+ DOM.classList.remove(...this.classNames)
31
+ this.classNames.length = 0
32
+ }
33
+
34
+ setHtmlAttributes(DOM: HTMLElement, descriptor: HTML) {
35
+ const keys = Object.keys(descriptor.htmlAttributes) as Array<keyof HtmlAttributes>
36
+ for (const key of keys) {
37
+ const value = descriptor.htmlAttributes[key]
38
+ if (key === 'style') {
39
+ DOM.style.cssText = ''
40
+ const style = camelcaseKeys(value as HTMLStyle) as any
41
+ if (descriptor.visible === false) style.display = 'none'
42
+ Object.assign(DOM.style, style)
43
+ } else if (key === 'classNames') {
44
+ this.setClassNames(DOM, descriptor.htmlAttributes.classNames)
45
+ } else {
46
+ const valueString = value?.toString() ?? ''
47
+ DOM.setAttribute(key, valueString)
48
+ }
49
+
50
+ }
51
+ }
52
+
53
+ cleanInteraction() {
54
+ for (const unlistener of this.unlisteners) unlistener()
55
+ this.unlisteners.length = 0
56
+ }
57
+
58
+ setHTMLInteraction(DOM: HTMLElement, descriptor: Descriptor) {
59
+ this.cleanInteraction()
60
+ const graphics = HTMLActor.getGraphics(this)
61
+ for (const interactionConfig of descriptor.interactions) {
62
+ if (interactionConfig.url) {
63
+ const interaction = Asset.get<Interaction>(interactionConfig.url)
64
+
65
+ const listener = (e: Event) => {
66
+ interaction.execute(interactionConfig.nodes, graphics, descriptor.uuid)
67
+ }
68
+ const eid = graphics.engine.inputSystem.listen(interactionConfig.type as any, listener, { target: DOM })
69
+ this.unlisteners.push(() => graphics.engine.inputSystem.unlisten(eid))
70
+ }
71
+ }
72
+ }
73
+
74
+ abstract add(actor: Actor): void
75
+
76
+ abstract remove(actor: Actor): void
77
+
78
+ abstract getDOM(): HTMLElement | null
79
+
80
+ abstract update(descriptor: HTML): void
81
+ }
@@ -0,0 +1,49 @@
1
+ import { createHTMLDOM } from "../utils"
2
+ import { HTMLService } from "../descriptor"
3
+ import { Actor } from "./Actor"
4
+ import { HTMLActor } from "./HTMLActor"
5
+
6
+ export class HTMLServiceActor extends HTMLActor {
7
+ private _wrapper: HTMLElement | null = null
8
+
9
+ constructor(uuid: string) {
10
+ super(uuid)
11
+ }
12
+
13
+ protected createWrapper() {
14
+ const DOM = createHTMLDOM(this.uuid)
15
+ return DOM
16
+ }
17
+
18
+ getDOM() {
19
+ if (this._wrapper === null) {
20
+ this._wrapper = this.createWrapper()
21
+ }
22
+
23
+ return this._wrapper
24
+ }
25
+
26
+ add(actor: Actor) {
27
+ if (actor instanceof HTMLActor) {
28
+ const child = actor.getDOM()
29
+ if (child === null) return
30
+ const DOM = this.getDOM()
31
+ if (DOM.contains(child)) return
32
+ DOM.appendChild(child)
33
+ }
34
+ }
35
+
36
+ remove(actor: Actor) {
37
+ if (actor instanceof HTMLActor) {
38
+ const child = actor.getDOM()
39
+ if (child === null) return
40
+ const DOM = this.getDOM()
41
+ if (DOM.contains(child)) DOM.removeChild(child)
42
+ }
43
+ }
44
+
45
+ update(descriptor: HTMLService) {
46
+ const DOM = this.getDOM()
47
+ this.setHtmlAttributes(DOM, descriptor)
48
+ }
49
+ }