@snaptrude/plugin-core 0.7.1 → 0.8.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.
Files changed (130) hide show
  1. package/CHANGELOG.md +14 -0
  2. package/api-manifest.full.json +6442 -0
  3. package/api-manifest.json +2029 -128
  4. package/dist/api/core/camera/index.d.ts +208 -0
  5. package/dist/api/core/camera/index.d.ts.map +1 -0
  6. package/dist/api/core/comment/index.d.ts +105 -2
  7. package/dist/api/core/comment/index.d.ts.map +1 -1
  8. package/dist/api/core/geom/create/index.d.ts +13 -13
  9. package/dist/api/core/geom/delete/index.d.ts +8 -2
  10. package/dist/api/core/geom/delete/index.d.ts.map +1 -1
  11. package/dist/api/core/geom/query/arc.d.ts +5 -5
  12. package/dist/api/core/geom/query/brep.d.ts +18 -18
  13. package/dist/api/core/geom/query/circle.d.ts +18 -18
  14. package/dist/api/core/geom/query/contour.d.ts +20 -20
  15. package/dist/api/core/geom/query/curve.d.ts +49 -49
  16. package/dist/api/core/geom/query/edge.d.ts +5 -5
  17. package/dist/api/core/geom/query/face.d.ts +16 -16
  18. package/dist/api/core/geom/query/halfedge.d.ts +8 -8
  19. package/dist/api/core/geom/query/profile.d.ts +19 -19
  20. package/dist/api/core/geom/query/vertex.d.ts +8 -8
  21. package/dist/api/core/geom/update/contour.d.ts +14 -14
  22. package/dist/api/core/geom/update/curve.d.ts +7 -7
  23. package/dist/api/core/geom/update/profile.d.ts +16 -16
  24. package/dist/api/core/handles/index.d.ts +210 -0
  25. package/dist/api/core/handles/index.d.ts.map +1 -0
  26. package/dist/api/core/index.d.ts +15 -0
  27. package/dist/api/core/index.d.ts.map +1 -1
  28. package/dist/api/core/io/export/index.d.ts +132 -0
  29. package/dist/api/core/io/export/index.d.ts.map +1 -0
  30. package/dist/api/core/io/import/index.d.ts +1 -1
  31. package/dist/api/core/io/index.d.ts +5 -0
  32. package/dist/api/core/io/index.d.ts.map +1 -1
  33. package/dist/api/core/layers.d.ts +7 -7
  34. package/dist/api/core/proposals/index.d.ts +65 -9
  35. package/dist/api/core/proposals/index.d.ts.map +1 -1
  36. package/dist/api/core/user.d.ts +44 -0
  37. package/dist/api/core/user.d.ts.map +1 -0
  38. package/dist/api/design/boolean/index.d.ts +4 -4
  39. package/dist/api/design/create/index.d.ts +139 -44
  40. package/dist/api/design/create/index.d.ts.map +1 -1
  41. package/dist/api/design/doors/index.d.ts +36 -0
  42. package/dist/api/design/doors/index.d.ts.map +1 -1
  43. package/dist/api/design/edit/index.d.ts +1 -1
  44. package/dist/api/design/erase/index.d.ts +2 -2
  45. package/dist/api/design/furniture/index.d.ts +114 -3
  46. package/dist/api/design/furniture/index.d.ts.map +1 -1
  47. package/dist/api/design/index.d.ts +10 -0
  48. package/dist/api/design/index.d.ts.map +1 -1
  49. package/dist/api/design/materials/index.d.ts +111 -14
  50. package/dist/api/design/materials/index.d.ts.map +1 -1
  51. package/dist/api/design/query/index.d.ts +31 -1
  52. package/dist/api/design/query/index.d.ts.map +1 -1
  53. package/dist/api/design/query/spaces.d.ts +5 -5
  54. package/dist/api/design/transform/index.d.ts +83 -14
  55. package/dist/api/design/transform/index.d.ts.map +1 -1
  56. package/dist/api/design/types/index.d.ts +181 -0
  57. package/dist/api/design/types/index.d.ts.map +1 -0
  58. package/dist/api/design/update/index.d.ts +335 -2
  59. package/dist/api/design/update/index.d.ts.map +1 -1
  60. package/dist/api/design/visibility.d.ts +98 -0
  61. package/dist/api/design/visibility.d.ts.map +1 -0
  62. package/dist/api/entity/referenceLine.d.ts +2 -2
  63. package/dist/api/entity/space.d.ts +19 -19
  64. package/dist/api/entity/story.d.ts +128 -15
  65. package/dist/api/entity/story.d.ts.map +1 -1
  66. package/dist/api/presentation/annotate.d.ts +448 -0
  67. package/dist/api/presentation/annotate.d.ts.map +1 -0
  68. package/dist/api/presentation/diagrams.d.ts +49 -8
  69. package/dist/api/presentation/diagrams.d.ts.map +1 -1
  70. package/dist/api/presentation/export.d.ts +104 -0
  71. package/dist/api/presentation/export.d.ts.map +1 -0
  72. package/dist/api/presentation/index.d.ts +38 -0
  73. package/dist/api/presentation/index.d.ts.map +1 -1
  74. package/dist/api/presentation/sheets.d.ts +410 -13
  75. package/dist/api/presentation/sheets.d.ts.map +1 -1
  76. package/dist/api/presentation/views.d.ts +165 -10
  77. package/dist/api/presentation/views.d.ts.map +1 -1
  78. package/dist/api/program/areas.d.ts +63 -3
  79. package/dist/api/program/areas.d.ts.map +1 -1
  80. package/dist/api/program/cores.d.ts +3 -99
  81. package/dist/api/program/cores.d.ts.map +1 -1
  82. package/dist/api/program/index.d.ts +2 -2
  83. package/dist/api/program/index.d.ts.map +1 -1
  84. package/dist/api/program/layout.d.ts +172 -12
  85. package/dist/api/program/layout.d.ts.map +1 -1
  86. package/dist/api/program/site.d.ts +11 -8
  87. package/dist/api/program/site.d.ts.map +1 -1
  88. package/dist/api/program/spreadsheet.d.ts +105 -13
  89. package/dist/api/program/spreadsheet.d.ts.map +1 -1
  90. package/dist/handles.d.ts +64 -25
  91. package/dist/handles.d.ts.map +1 -1
  92. package/dist/index.cjs +2316 -1644
  93. package/dist/index.cjs.map +1 -1
  94. package/dist/index.js +2224 -1639
  95. package/dist/index.js.map +1 -1
  96. package/package.json +1 -1
  97. package/src/api/core/camera/index.ts +212 -0
  98. package/src/api/core/comment/index.ts +120 -2
  99. package/src/api/core/geom/delete/index.ts +6 -0
  100. package/src/api/core/handles/index.ts +233 -0
  101. package/src/api/core/index.ts +15 -0
  102. package/src/api/core/io/export/index.ts +124 -0
  103. package/src/api/core/io/index.ts +5 -0
  104. package/src/api/core/proposals/index.ts +71 -11
  105. package/src/api/core/user.ts +46 -0
  106. package/src/api/design/create/index.ts +166 -36
  107. package/src/api/design/doors/index.ts +40 -0
  108. package/src/api/design/furniture/index.ts +127 -3
  109. package/src/api/design/index.ts +10 -0
  110. package/src/api/design/materials/index.ts +157 -30
  111. package/src/api/design/query/index.ts +33 -7
  112. package/src/api/design/transform/index.ts +89 -12
  113. package/src/api/design/types/index.ts +156 -0
  114. package/src/api/design/update/index.ts +402 -6
  115. package/src/api/design/visibility.ts +109 -0
  116. package/src/api/entity/story.ts +141 -15
  117. package/src/api/presentation/annotate.ts +360 -0
  118. package/src/api/presentation/diagrams.ts +53 -8
  119. package/src/api/presentation/export.ts +104 -0
  120. package/src/api/presentation/index.ts +46 -0
  121. package/src/api/presentation/sheets.ts +346 -13
  122. package/src/api/presentation/views.ts +164 -12
  123. package/src/api/program/areas.ts +57 -6
  124. package/src/api/program/cores.ts +3 -91
  125. package/src/api/program/index.ts +2 -2
  126. package/src/api/program/layout.ts +182 -12
  127. package/src/api/program/site.ts +11 -8
  128. package/src/api/program/spreadsheet.ts +125 -29
  129. package/src/handles.ts +77 -13
  130. package/tsconfig.json +7 -2
@@ -7,12 +7,12 @@ import { PluginDesignChangeResult } from "../lock"
7
7
  * `snaptrude.design.transform` — rigid transforms on scene entities.
8
8
  *
9
9
  * `move` / `rotate` migrated from the removed `tools.transform.*`; `align` snaps a
10
- * set of components' bounding-box edges to each other (or to a reference). All ops
11
- * are undoable and return {@linkcode PluginDesignChangeResult} `{ affected }`;
12
- * failures throw (RPC rejects).
10
+ * set of components' bounding-box edges to each other (or to a reference); `mirror`
11
+ * flips components in place about a horizontal axis. All ops are undoable and return
12
+ * {@linkcode PluginDesignChangeResult} `{ affected }`; failures throw (RPC rejects).
13
13
  *
14
- * `mirror` / `getPosition` / `setPosition` (and `scale`, an engine gap) are NOT in
15
- * this surface yet — they are a later, non-migration pass.
14
+ * `getPosition` / `setPosition` (and `scale`, an engine gap) are NOT in this surface
15
+ * yet — they are a later pass.
16
16
  */
17
17
  export abstract class PluginDesignTransformApi {
18
18
  constructor() {}
@@ -45,30 +45,37 @@ export abstract class PluginDesignTransformApi {
45
45
  ): PluginApiReturn<PluginDesignChangeResult>
46
46
 
47
47
  /**
48
- * Rotate entities by a **signed angle in DEGREES**, anchored at the combined
49
- * bounding-box centre (positive = CCW about +Y). NOTE: unlike the removed
50
- * `tools.transform.rotate` (radians + caller pivot), this canonical form takes
51
- * DEGREES and has NO caller pivot — the pivot is always the bbox centre. Undoable.
48
+ * Rotate entities by a **signed angle in DEGREES** (positive = CCW about +Y).
49
+ * The pivot defaults to the combined bounding-box centre; pass `options.pivot`
50
+ * to rotate about an explicit world-space point instead. NOTE: unlike the
51
+ * removed `tools.transform.rotate` (radians), this canonical form takes
52
+ * DEGREES. Undoable.
52
53
  *
53
54
  * @param components - Entities to rotate
54
55
  * @param angleInDegrees - Signed rotation angle in degrees
55
- * @param options - `axis` (defaults to world +Y), `is2D`
56
+ * @param options - `axis` (defaults to world +Y), `pivot` (world-space rotation
57
+ * centre as a {@linkcode Vec3Handle}; defaults to the combined bbox centre),
58
+ * `is2D`
56
59
  * @returns {@linkcode PluginDesignChangeResult}
57
60
  *
58
61
  * @examplePrompt Rotate the selected building 90 degrees
59
62
  * @examplePrompt Turn this room 45 degrees clockwise
60
63
  * @examplePrompt Spin the furniture block 180 degrees about its centre
61
64
  * @examplePrompt Rotate these masses 30 degrees around the vertical axis
65
+ * @examplePrompt Rotate these walls 90 degrees about the origin
62
66
  *
63
67
  * # Example
64
68
  * ```ts
65
69
  * await snaptrude.design.transform.rotate(["space-id"], 90)
70
+ * // …or rotate about an explicit pivot point
71
+ * const { vec3 } = snaptrude.core.math
72
+ * await snaptrude.design.transform.rotate(["space-id"], 90, { pivot: vec3.new(0, 0, 0) })
66
73
  * ```
67
74
  */
68
75
  public abstract rotate(
69
76
  components: ComponentHandle[],
70
77
  angleInDegrees: number,
71
- options?: { axis?: Vec3Handle; is2D?: boolean },
78
+ options?: { axis?: Vec3Handle; pivot?: Vec3Handle; is2D?: boolean },
72
79
  ): PluginApiReturn<PluginDesignChangeResult>
73
80
 
74
81
  /**
@@ -116,14 +123,69 @@ export abstract class PluginDesignTransformApi {
116
123
  edge: PluginAlignEdge,
117
124
  options?: { reference?: ComponentHandle },
118
125
  ): PluginApiReturn<PluginDesignChangeResult>
126
+
127
+ /**
128
+ * Mirror components **in place** about a horizontal axis, flipping their geometry
129
+ * across that axis through the combined bounding-box centre (the mesh's
130
+ * world-matrix flip + brep inversion + CAD/dimension-line/parametric handling
131
+ * commit atomically). Nothing moves off-centre — this is the toolbar "flip", not
132
+ * a translate-and-reflect. Undoable.
133
+ *
134
+ * `axis` names the axis the geometry mirrors **across** (world axes, Y is up):
135
+ * - `'x'` — mirror across world X (a front↔back flip in plan; reflects the Z coord)
136
+ * - `'z'` — mirror across world Z (a left↔right flip in plan; reflects the X coord)
137
+ *
138
+ * Vertical (`'y'`) mirroring is intentionally not exposed. Locked, bucket-locked
139
+ * and ineligible entries (terrain, plinths, reference/dimension lines,
140
+ * neighbourhood buildings) are **silently dropped**; the call only throws if
141
+ * nothing mirrorable remains. `affected` echoes the supplied handles.
142
+ *
143
+ * @param components - Entities to mirror (≥1)
144
+ * @param axis - Axis to mirror across ({@linkcode PluginTransformMirrorAxis})
145
+ * @returns {@linkcode PluginDesignChangeResult}
146
+ *
147
+ * @examplePrompt Mirror the selected building across the x axis
148
+ * @examplePrompt Flip these rooms left to right
149
+ * @examplePrompt Mirror this furniture block horizontally
150
+ * @examplePrompt Flip the selected walls front to back
151
+ * @examplePrompt Create a mirror image of these masses about the z axis
152
+ *
153
+ * # Example
154
+ * ```ts
155
+ * const rooms = await snaptrude.design.selection.get()
156
+ * await snaptrude.design.transform.mirror(rooms, "x")
157
+ * ```
158
+ */
159
+ public abstract mirror(
160
+ components: ComponentHandle[],
161
+ axis: PluginTransformMirrorAxis,
162
+ ): PluginApiReturn<PluginDesignChangeResult>
119
163
  }
120
164
 
165
+ /**
166
+ * The horizontal axis a {@linkcode PluginDesignTransformApi.mirror} flips **across**
167
+ * (world axes, Y up): `'x'` mirrors across world X (front↔back in plan; reflects Z),
168
+ * `'z'` mirrors across world Z (left↔right in plan; reflects X). Vertical (`'y'`)
169
+ * mirroring is not exposed.
170
+ */
171
+ export const PluginTransformMirrorAxis = z.enum(["x", "z"])
172
+ export type PluginTransformMirrorAxis = z.infer<
173
+ typeof PluginTransformMirrorAxis
174
+ >
175
+
121
176
  /**
122
177
  * The bounding-box edge an {@linkcode PluginDesignTransformApi.align} snaps to.
123
178
  * Mirrors the engine's align `DirectionType`. World-axis mapping: `left`/`right`/`center`
124
179
  * → world X min/max/mid; `top`/`bottom`/`middle` → world Z max/min/mid.
125
180
  */
126
- export const PluginAlignEdge = z.enum(["left", "right", "center", "top", "bottom", "middle"])
181
+ export const PluginAlignEdge = z.enum([
182
+ "left",
183
+ "right",
184
+ "center",
185
+ "top",
186
+ "bottom",
187
+ "middle",
188
+ ])
127
189
  export type PluginAlignEdge = z.infer<typeof PluginAlignEdge>
128
190
 
129
191
  /**
@@ -145,6 +207,7 @@ export const PluginDesignRotateArgs = z.object({
145
207
  angleInDegrees: z.number(),
146
208
  axis: Vec3Handle.optional(),
147
209
  is2D: z.boolean().optional(),
210
+ pivot: Vec3Handle.optional(),
148
211
  })
149
212
  export type PluginDesignRotateArgs = z.infer<typeof PluginDesignRotateArgs>
150
213
 
@@ -163,3 +226,17 @@ export const PluginDesignAlignArgs = z.object({
163
226
  reference: ComponentHandle.optional(),
164
227
  })
165
228
  export type PluginDesignAlignArgs = z.infer<typeof PluginDesignAlignArgs>
229
+
230
+ /**
231
+ * Arguments for {@linkcode PluginDesignTransformApi.mirror}.
232
+ *
233
+ * | Property | Type | Description |
234
+ * |---|---|---|
235
+ * | `components` | {@linkcode ComponentHandle}`[]` | Entities to mirror (≥1) |
236
+ * | `axis` | {@linkcode PluginTransformMirrorAxis} | Horizontal axis to mirror across (`'x'` \| `'z'`) |
237
+ */
238
+ export const PluginDesignMirrorArgs = z.object({
239
+ components: z.array(ComponentHandle).min(1),
240
+ axis: PluginTransformMirrorAxis,
241
+ })
242
+ export type PluginDesignMirrorArgs = z.infer<typeof PluginDesignMirrorArgs>
@@ -0,0 +1,156 @@
1
+ import * as z from "zod"
2
+ import { PluginApiReturn } from "../../../types"
3
+
4
+ /**
5
+ * `snaptrude.design.types` — READ-ONLY reference over the project's building
6
+ * **type / assembly** system (the Project Properties layer stacks: External /
7
+ * Internal walls, slabs, floors, ceilings, roofs). A type bundles a labelled
8
+ * layer stack — each layer's role, thickness (engine units) and material — plus a
9
+ * summed total thickness. Both the built-in defaults and any team/user-added types
10
+ * are surfaced.
11
+ *
12
+ * Types are plain value records ({@linkcode PluginBuildingType}) — NOT scene
13
+ * entities/handles. A type's `id` is a stable `"<kind>:<name>"` token
14
+ * (e.g. `"wall:brickWithPlasterAndPaint"`) returned by
15
+ * {@linkcode PluginDesignTypesApi.list} and consumed by
16
+ * {@linkcode PluginDesignTypesApi.get}. Reads never throw — an unknown id yields
17
+ * `null`; a kind with no types yields `[]`.
18
+ *
19
+ * These are reads only: there is no engine seam to author a type from a plugin
20
+ * (types are created through the construction/project-properties UI).
21
+ */
22
+ export abstract class PluginDesignTypesApi {
23
+ constructor() {}
24
+
25
+ /**
26
+ * List the building types of one `kind` (wall / slab / floor / ceiling / roof)
27
+ * — the built-in defaults plus any team/user-added types. Returns lightweight
28
+ * summaries; call {@linkcode PluginDesignTypesApi.get} for the full layer stack.
29
+ *
30
+ * @param kind Which family of types to list
31
+ * @returns The type summaries as {@linkcode PluginBuildingTypeSummary}`[]` (`[]` when none)
32
+ *
33
+ * @examplePrompt What wall types does this project have?
34
+ * @examplePrompt List the available slab assemblies
35
+ * @examplePrompt Show me every roof type in the project
36
+ * @examplePrompt Which floor types can I use?
37
+ *
38
+ * # Example
39
+ * ```ts
40
+ * const wallTypes = await snaptrude.design.types.list("wall")
41
+ * for (const t of wallTypes) console.log(t.id, t.label, t.thickness)
42
+ * ```
43
+ */
44
+ public abstract list(
45
+ kind: PluginBuildingTypeKind
46
+ ): PluginApiReturn<PluginBuildingTypeSummary[]>
47
+
48
+ /**
49
+ * Get one building type by its `"<kind>:<name>"` id — its labelled layer stack
50
+ * (each layer's role, thickness and material) plus the summed total thickness.
51
+ *
52
+ * @param typeId The type id from {@linkcode PluginDesignTypesApi.list} (e.g. `"wall:exposedConcrete"`)
53
+ * @returns The full type, or `null` if no type matches
54
+ *
55
+ * @examplePrompt What layers make up this wall type?
56
+ * @examplePrompt Show the construction of the exposed-concrete wall
57
+ * @examplePrompt What's the total thickness of this slab type?
58
+ * @examplePrompt Which materials are in this roof assembly?
59
+ *
60
+ * # Example
61
+ * ```ts
62
+ * const [first] = await snaptrude.design.types.list("wall")
63
+ * const type = await snaptrude.design.types.get(first.id)
64
+ * if (type) for (const layer of type.layers) console.log(layer.name, layer.thickness)
65
+ * ```
66
+ */
67
+ public abstract get(typeId: string): PluginApiReturn<PluginBuildingType | null>
68
+ }
69
+
70
+ /** The building-type families exposed by {@linkcode PluginDesignTypesApi}. */
71
+ export const PluginBuildingTypeKind = z.enum(["wall", "slab", "floor", "ceiling", "roof"])
72
+ export type PluginBuildingTypeKind = z.infer<typeof PluginBuildingTypeKind>
73
+
74
+ /**
75
+ * One layer of a building type's assembly.
76
+ *
77
+ * | Property | Type | Description |
78
+ * |---|---|---|
79
+ * | `name` | `string` | Layer name (e.g. `"RCC"`, `"Paint"`) |
80
+ * | `role` | `string` | Layer role (e.g. `"Structure"`, `"Finish"`) |
81
+ * | `thickness` | `number` | Layer thickness in engine units (project's active unit mode) |
82
+ * | `material` | `object`? | Layer material — `{ name, type }` (optional) |
83
+ */
84
+ export const PluginTypeLayer = z.object({
85
+ name: z.string(),
86
+ role: z.string(),
87
+ thickness: z.number(),
88
+ material: z
89
+ .object({
90
+ name: z.string(),
91
+ type: z.string(),
92
+ })
93
+ .optional(),
94
+ })
95
+ export type PluginTypeLayer = z.infer<typeof PluginTypeLayer>
96
+
97
+ /**
98
+ * A lightweight building-type summary (no layer stack).
99
+ *
100
+ * | Property | Type | Description |
101
+ * |---|---|---|
102
+ * | `id` | `string` | Stable `"<kind>:<name>"` token — pass to `design.types.get` |
103
+ * | `kind` | {@linkcode PluginBuildingTypeKind} | Which family it belongs to |
104
+ * | `label` | `string` | Human-readable label |
105
+ * | `isDefault` | `boolean` | `true` for a built-in type, `false` for a team/user type |
106
+ * | `thickness` | `number` | Summed layer thickness in engine units |
107
+ */
108
+ export const PluginBuildingTypeSummary = z.object({
109
+ id: z.string(),
110
+ kind: PluginBuildingTypeKind,
111
+ label: z.string(),
112
+ isDefault: z.boolean(),
113
+ thickness: z.number(),
114
+ })
115
+ export type PluginBuildingTypeSummary = z.infer<typeof PluginBuildingTypeSummary>
116
+
117
+ /**
118
+ * A full building type — a {@linkcode PluginBuildingTypeSummary} plus its layer stack.
119
+ *
120
+ * | Property | Type | Description |
121
+ * |---|---|---|
122
+ * | `id` | `string` | Stable `"<kind>:<name>"` token |
123
+ * | `kind` | {@linkcode PluginBuildingTypeKind} | Which family it belongs to |
124
+ * | `label` | `string` | Human-readable label |
125
+ * | `isDefault` | `boolean` | `true` for a built-in type |
126
+ * | `thickness` | `number` | Summed layer thickness in engine units |
127
+ * | `layers` | {@linkcode PluginTypeLayer}`[]` | The ordered layer stack |
128
+ */
129
+ export const PluginBuildingType = PluginBuildingTypeSummary.extend({
130
+ layers: z.array(PluginTypeLayer),
131
+ })
132
+ export type PluginBuildingType = z.infer<typeof PluginBuildingType>
133
+
134
+ /**
135
+ * Arguments for {@linkcode PluginDesignTypesApi.list}.
136
+ *
137
+ * | Property | Type | Description |
138
+ * |---|---|---|
139
+ * | `kind` | {@linkcode PluginBuildingTypeKind} | Which family of types to list |
140
+ */
141
+ export const PluginDesignTypesListArgs = z.object({
142
+ kind: PluginBuildingTypeKind,
143
+ })
144
+ export type PluginDesignTypesListArgs = z.infer<typeof PluginDesignTypesListArgs>
145
+
146
+ /**
147
+ * Arguments for {@linkcode PluginDesignTypesApi.get}.
148
+ *
149
+ * | Property | Type | Description |
150
+ * |---|---|---|
151
+ * | `typeId` | `string` | The `"<kind>:<name>"` id from `design.types.list` |
152
+ */
153
+ export const PluginDesignTypesGetArgs = z.object({
154
+ typeId: z.string(),
155
+ })
156
+ export type PluginDesignTypesGetArgs = z.infer<typeof PluginDesignTypesGetArgs>