fastapi-voyager 0.15.0__py3-none-any.whl → 0.15.2__py3-none-any.whl
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.
- fastapi_voyager/er_diagram.py +57 -109
- fastapi_voyager/render.py +12 -2
- fastapi_voyager/server.py +1 -0
- fastapi_voyager/templates/dot/er_diagram.j2 +29 -0
- fastapi_voyager/version.py +1 -1
- fastapi_voyager/web/component/demo.js +5 -5
- fastapi_voyager/web/component/render-graph.js +60 -61
- fastapi_voyager/web/component/route-code-display.js +35 -37
- fastapi_voyager/web/component/schema-code-display.js +50 -53
- fastapi_voyager/web/graph-ui.js +90 -101
- fastapi_voyager/web/graphviz.svg.css +10 -10
- fastapi_voyager/web/graphviz.svg.js +306 -316
- fastapi_voyager/web/icon/site.webmanifest +11 -1
- fastapi_voyager/web/index.html +263 -110
- fastapi_voyager/web/store.js +109 -111
- fastapi_voyager/web/vue-main.js +329 -263
- {fastapi_voyager-0.15.0.dist-info → fastapi_voyager-0.15.2.dist-info}/METADATA +16 -4
- {fastapi_voyager-0.15.0.dist-info → fastapi_voyager-0.15.2.dist-info}/RECORD +21 -20
- {fastapi_voyager-0.15.0.dist-info → fastapi_voyager-0.15.2.dist-info}/WHEEL +0 -0
- {fastapi_voyager-0.15.0.dist-info → fastapi_voyager-0.15.2.dist-info}/entry_points.txt +0 -0
- {fastapi_voyager-0.15.0.dist-info → fastapi_voyager-0.15.2.dist-info}/licenses/LICENSE +0 -0
|
@@ -1,21 +1,21 @@
|
|
|
1
|
-
|
|
2
|
-
"use strict"
|
|
1
|
+
;+(function ($) {
|
|
2
|
+
"use strict"
|
|
3
3
|
|
|
4
4
|
// GRAPHVIZSVG PUBLIC CLASS DEFINITION
|
|
5
5
|
// ===================================
|
|
6
6
|
|
|
7
7
|
var GraphvizSvg = function (element, options) {
|
|
8
|
-
this.type = null
|
|
9
|
-
this.options = null
|
|
10
|
-
this.enabled = null
|
|
11
|
-
this.$element = null
|
|
8
|
+
this.type = null
|
|
9
|
+
this.options = null
|
|
10
|
+
this.enabled = null
|
|
11
|
+
this.$element = null
|
|
12
12
|
|
|
13
|
-
this.init("graphviz.svg", element, options)
|
|
14
|
-
}
|
|
13
|
+
this.init("graphviz.svg", element, options)
|
|
14
|
+
}
|
|
15
15
|
|
|
16
|
-
GraphvizSvg.VERSION = "1.0.1"
|
|
16
|
+
GraphvizSvg.VERSION = "1.0.1"
|
|
17
17
|
|
|
18
|
-
GraphvizSvg.GVPT_2_PX = 32.5
|
|
18
|
+
GraphvizSvg.GVPT_2_PX = 32.5 // used to ease removal of extra space
|
|
19
19
|
|
|
20
20
|
GraphvizSvg.DEFAULTS = {
|
|
21
21
|
url: null,
|
|
@@ -25,7 +25,7 @@
|
|
|
25
25
|
pointerCursor: true,
|
|
26
26
|
tooltips: {
|
|
27
27
|
init: function ($graph) {
|
|
28
|
-
var $a = $(this)
|
|
28
|
+
var $a = $(this)
|
|
29
29
|
$a.tooltip({
|
|
30
30
|
container: $graph,
|
|
31
31
|
placement: "left",
|
|
@@ -34,200 +34,200 @@
|
|
|
34
34
|
}).on("hide.bs.tooltip", function () {
|
|
35
35
|
// keep them visible even if you acidentally mouse over
|
|
36
36
|
if ($a.attr("data-tooltip-keepvisible")) {
|
|
37
|
-
return false
|
|
37
|
+
return false
|
|
38
38
|
}
|
|
39
|
-
})
|
|
39
|
+
})
|
|
40
40
|
},
|
|
41
41
|
show: function () {
|
|
42
|
-
var $a = $(this)
|
|
43
|
-
$a.attr("data-tooltip-keepvisible", true)
|
|
44
|
-
$a.tooltip("show")
|
|
42
|
+
var $a = $(this)
|
|
43
|
+
$a.attr("data-tooltip-keepvisible", true)
|
|
44
|
+
$a.tooltip("show")
|
|
45
45
|
},
|
|
46
46
|
hide: function () {
|
|
47
|
-
var $a = $(this)
|
|
48
|
-
$a.removeAttr("data-tooltip-keepvisible")
|
|
49
|
-
$a.tooltip("hide")
|
|
47
|
+
var $a = $(this)
|
|
48
|
+
$a.removeAttr("data-tooltip-keepvisible")
|
|
49
|
+
$a.tooltip("hide")
|
|
50
50
|
},
|
|
51
51
|
update: function () {
|
|
52
|
-
var $this = $(this)
|
|
52
|
+
var $this = $(this)
|
|
53
53
|
if ($this.attr("data-tooltip-keepvisible")) {
|
|
54
|
-
$this.tooltip("show")
|
|
55
|
-
return
|
|
54
|
+
$this.tooltip("show")
|
|
55
|
+
return
|
|
56
56
|
}
|
|
57
57
|
},
|
|
58
58
|
},
|
|
59
59
|
zoom: true,
|
|
60
60
|
highlight: {
|
|
61
61
|
selected: function (col, bg) {
|
|
62
|
-
return col
|
|
62
|
+
return col
|
|
63
63
|
},
|
|
64
64
|
unselected: function (col, bg) {
|
|
65
|
-
return jQuery.Color(col).transition(bg, 0.9)
|
|
65
|
+
return jQuery.Color(col).transition(bg, 0.9)
|
|
66
66
|
},
|
|
67
67
|
},
|
|
68
68
|
ready: null,
|
|
69
|
-
}
|
|
69
|
+
}
|
|
70
70
|
|
|
71
71
|
GraphvizSvg.prototype.init = function (type, element, options) {
|
|
72
|
-
this.enabled = true
|
|
73
|
-
this.type = type
|
|
74
|
-
this.$element = $(element)
|
|
75
|
-
this.options = this.getOptions(options)
|
|
72
|
+
this.enabled = true
|
|
73
|
+
this.type = type
|
|
74
|
+
this.$element = $(element)
|
|
75
|
+
this.options = this.getOptions(options)
|
|
76
76
|
|
|
77
77
|
if (options.url) {
|
|
78
|
-
var that = this
|
|
78
|
+
var that = this
|
|
79
79
|
$.get(
|
|
80
80
|
options.url,
|
|
81
81
|
null,
|
|
82
82
|
function (data) {
|
|
83
|
-
var svg = $("svg", data)
|
|
84
|
-
that.$element.html(document.adoptNode(svg[0]))
|
|
85
|
-
that.setup()
|
|
83
|
+
var svg = $("svg", data)
|
|
84
|
+
that.$element.html(document.adoptNode(svg[0]))
|
|
85
|
+
that.setup()
|
|
86
86
|
},
|
|
87
87
|
"xml"
|
|
88
|
-
)
|
|
88
|
+
)
|
|
89
89
|
} else {
|
|
90
90
|
if (options.svg) {
|
|
91
|
-
this.$element.html(options.svg)
|
|
91
|
+
this.$element.html(options.svg)
|
|
92
92
|
}
|
|
93
|
-
this.setup()
|
|
93
|
+
this.setup()
|
|
94
94
|
}
|
|
95
|
-
}
|
|
95
|
+
}
|
|
96
96
|
|
|
97
97
|
GraphvizSvg.prototype.getDefaults = function () {
|
|
98
|
-
return GraphvizSvg.DEFAULTS
|
|
99
|
-
}
|
|
98
|
+
return GraphvizSvg.DEFAULTS
|
|
99
|
+
}
|
|
100
100
|
|
|
101
101
|
GraphvizSvg.prototype.getOptions = function (options) {
|
|
102
|
-
options = $.extend({}, this.getDefaults(), this.$element.data(), options)
|
|
102
|
+
options = $.extend({}, this.getDefaults(), this.$element.data(), options)
|
|
103
103
|
|
|
104
104
|
if (options.shrink) {
|
|
105
105
|
if (typeof options.shrink != "object") {
|
|
106
106
|
options.shrink = {
|
|
107
107
|
x: options.shrink,
|
|
108
108
|
y: options.shrink,
|
|
109
|
-
}
|
|
109
|
+
}
|
|
110
110
|
}
|
|
111
|
-
options.shrink.x = this.convertToPx(options.shrink.x)
|
|
112
|
-
options.shrink.y = this.convertToPx(options.shrink.y)
|
|
111
|
+
options.shrink.x = this.convertToPx(options.shrink.x)
|
|
112
|
+
options.shrink.y = this.convertToPx(options.shrink.y)
|
|
113
113
|
}
|
|
114
|
-
return options
|
|
115
|
-
}
|
|
114
|
+
return options
|
|
115
|
+
}
|
|
116
116
|
|
|
117
117
|
GraphvizSvg.prototype.setup = function () {
|
|
118
|
-
var options = this.options
|
|
118
|
+
var options = this.options
|
|
119
119
|
|
|
120
120
|
// save key elements in the graph for easy access
|
|
121
|
-
var $svg = $(this.$element.children("svg"))
|
|
122
|
-
var $graph = $svg.children("g:first")
|
|
123
|
-
this.$svg = $svg
|
|
124
|
-
this.$graph = $graph
|
|
125
|
-
this.$background = $graph.children("polygon:first")
|
|
126
|
-
this.$nodes = $graph.children(".node")
|
|
127
|
-
this.$edges = $graph.children(".edge")
|
|
128
|
-
this.$clusters = $graph.children(".cluster")
|
|
129
|
-
this._nodesByName = {}
|
|
130
|
-
this._edgesByName = {}
|
|
131
|
-
this._clustersByName = {}
|
|
121
|
+
var $svg = $(this.$element.children("svg"))
|
|
122
|
+
var $graph = $svg.children("g:first")
|
|
123
|
+
this.$svg = $svg
|
|
124
|
+
this.$graph = $graph
|
|
125
|
+
this.$background = $graph.children("polygon:first") // might not exist
|
|
126
|
+
this.$nodes = $graph.children(".node")
|
|
127
|
+
this.$edges = $graph.children(".edge")
|
|
128
|
+
this.$clusters = $graph.children(".cluster")
|
|
129
|
+
this._nodesByName = {}
|
|
130
|
+
this._edgesByName = {}
|
|
131
|
+
this._clustersByName = {}
|
|
132
132
|
|
|
133
133
|
// add top level class and copy background color to element
|
|
134
|
-
this.$element.addClass("graphviz-svg")
|
|
134
|
+
this.$element.addClass("graphviz-svg")
|
|
135
135
|
if (this.$background.length) {
|
|
136
|
-
this.$element.css("background", this.$background.attr("fill"))
|
|
136
|
+
this.$element.css("background", this.$background.attr("fill"))
|
|
137
137
|
}
|
|
138
138
|
|
|
139
139
|
// setup all the nodes and edges
|
|
140
|
-
var that = this
|
|
140
|
+
var that = this
|
|
141
141
|
this.$nodes.each(function () {
|
|
142
142
|
$(this).attr({
|
|
143
143
|
"pointer-events": "visible",
|
|
144
|
-
})
|
|
145
|
-
that.setupNodesEdges($(this), "node")
|
|
146
|
-
})
|
|
144
|
+
})
|
|
145
|
+
that.setupNodesEdges($(this), "node")
|
|
146
|
+
})
|
|
147
147
|
this.$edges.each(function () {
|
|
148
|
-
that.setupNodesEdges($(this), "edge")
|
|
149
|
-
})
|
|
148
|
+
that.setupNodesEdges($(this), "edge")
|
|
149
|
+
})
|
|
150
150
|
this.$clusters.each(function () {
|
|
151
|
-
that.setupNodesEdges($(this), "cluster")
|
|
152
|
-
})
|
|
151
|
+
that.setupNodesEdges($(this), "cluster")
|
|
152
|
+
})
|
|
153
153
|
|
|
154
154
|
// remove the graph title element
|
|
155
|
-
var $title = this.$graph.children("title")
|
|
156
|
-
this.$graph.attr("data-name", $title.text())
|
|
157
|
-
$title.remove()
|
|
155
|
+
var $title = this.$graph.children("title")
|
|
156
|
+
this.$graph.attr("data-name", $title.text())
|
|
157
|
+
$title.remove()
|
|
158
158
|
|
|
159
159
|
if (options.zoom) {
|
|
160
|
-
this.setupZoom()
|
|
160
|
+
this.setupZoom()
|
|
161
161
|
}
|
|
162
162
|
|
|
163
163
|
// tell people we're done
|
|
164
164
|
if (options.ready) {
|
|
165
|
-
options.ready.call(this)
|
|
165
|
+
options.ready.call(this)
|
|
166
166
|
}
|
|
167
|
-
}
|
|
167
|
+
}
|
|
168
168
|
|
|
169
169
|
GraphvizSvg.prototype.setupNodesEdges = function ($el, type) {
|
|
170
|
-
var that = this
|
|
171
|
-
var options = this.options
|
|
170
|
+
var that = this
|
|
171
|
+
var options = this.options
|
|
172
172
|
|
|
173
173
|
if (type === "edge" && options.edgeHitPadding) {
|
|
174
|
-
this.ensureEdgeHitArea($el, options.edgeHitPadding)
|
|
174
|
+
this.ensureEdgeHitArea($el, options.edgeHitPadding)
|
|
175
175
|
}
|
|
176
176
|
|
|
177
177
|
if (options.pointerCursor && (type === "edge" || type === "node")) {
|
|
178
|
-
this.setInteractiveCursor($el, type === "edge")
|
|
178
|
+
this.setInteractiveCursor($el, type === "edge")
|
|
179
179
|
}
|
|
180
180
|
|
|
181
181
|
// save the colors of the paths, ellipses and polygons
|
|
182
182
|
$el.find("polygon, ellipse, path").each(function () {
|
|
183
|
-
var $this = $(this)
|
|
183
|
+
var $this = $(this)
|
|
184
184
|
if ($this.attr("data-graphviz-hitbox") === "true") {
|
|
185
|
-
return
|
|
185
|
+
return
|
|
186
186
|
}
|
|
187
187
|
// save original colors
|
|
188
188
|
$this.data("graphviz.svg.color", {
|
|
189
189
|
fill: $this.attr("fill"),
|
|
190
190
|
stroke: $this.attr("stroke"),
|
|
191
|
-
})
|
|
191
|
+
})
|
|
192
192
|
|
|
193
193
|
// shrink it if it's a node
|
|
194
194
|
if (type === "node" && options.shrink) {
|
|
195
|
-
that.scaleNode($this)
|
|
195
|
+
that.scaleNode($this)
|
|
196
196
|
}
|
|
197
|
-
})
|
|
197
|
+
})
|
|
198
198
|
|
|
199
199
|
// save the node name and check if theres a comment above; save it
|
|
200
|
-
var $title = $el.children("title")
|
|
200
|
+
var $title = $el.children("title")
|
|
201
201
|
if ($title[0]) {
|
|
202
202
|
// remove any compass points:
|
|
203
|
-
var title = $title.text().replace(/:[snew][ew]?/g, "")
|
|
204
|
-
$el.attr("data-name", title)
|
|
205
|
-
$title.remove()
|
|
203
|
+
var title = $title.text().replace(/:[snew][ew]?/g, "")
|
|
204
|
+
$el.attr("data-name", title)
|
|
205
|
+
$title.remove()
|
|
206
206
|
if (type === "node") {
|
|
207
|
-
this._nodesByName[title] = $el[0]
|
|
207
|
+
this._nodesByName[title] = $el[0]
|
|
208
208
|
} else if (type === "edge") {
|
|
209
209
|
if (!this._edgesByName[title]) {
|
|
210
|
-
this._edgesByName[title] = []
|
|
210
|
+
this._edgesByName[title] = []
|
|
211
211
|
}
|
|
212
|
-
this._edgesByName[title].push($el[0])
|
|
212
|
+
this._edgesByName[title].push($el[0])
|
|
213
213
|
} else if (type === "cluster") {
|
|
214
|
-
this._clustersByName[title] = $el[0]
|
|
214
|
+
this._clustersByName[title] = $el[0]
|
|
215
215
|
}
|
|
216
216
|
// without a title we can't tell if its a user comment or not
|
|
217
|
-
var previousSibling = $el[0].previousSibling
|
|
217
|
+
var previousSibling = $el[0].previousSibling
|
|
218
218
|
while (previousSibling && previousSibling.nodeType != 8) {
|
|
219
|
-
previousSibling = previousSibling.previousSibling
|
|
219
|
+
previousSibling = previousSibling.previousSibling
|
|
220
220
|
}
|
|
221
221
|
if (previousSibling != null && previousSibling.nodeType == 8) {
|
|
222
222
|
var htmlDecode = function (input) {
|
|
223
|
-
var e = document.createElement("div")
|
|
224
|
-
e.innerHTML = input
|
|
225
|
-
return e.childNodes[0].nodeValue
|
|
226
|
-
}
|
|
227
|
-
var value = htmlDecode(previousSibling.nodeValue.trim())
|
|
223
|
+
var e = document.createElement("div")
|
|
224
|
+
e.innerHTML = input
|
|
225
|
+
return e.childNodes[0].nodeValue
|
|
226
|
+
}
|
|
227
|
+
var value = htmlDecode(previousSibling.nodeValue.trim())
|
|
228
228
|
if (value != title) {
|
|
229
229
|
// user added comment
|
|
230
|
-
$el.attr("data-comment", value)
|
|
230
|
+
$el.attr("data-comment", value)
|
|
231
231
|
}
|
|
232
232
|
}
|
|
233
233
|
}
|
|
@@ -236,427 +236,417 @@
|
|
|
236
236
|
$el
|
|
237
237
|
.find("a")
|
|
238
238
|
.filter(function () {
|
|
239
|
-
return $(this).attr("xlink:title")
|
|
239
|
+
return $(this).attr("xlink:title")
|
|
240
240
|
})
|
|
241
241
|
.each(function () {
|
|
242
|
-
var $a = $(this)
|
|
243
|
-
$a.attr("title", $a.attr("xlink:title"))
|
|
244
|
-
$a.removeAttr("xlink:title")
|
|
242
|
+
var $a = $(this)
|
|
243
|
+
$a.attr("title", $a.attr("xlink:title"))
|
|
244
|
+
$a.removeAttr("xlink:title")
|
|
245
245
|
if (options.tooltips) {
|
|
246
|
-
options.tooltips.init.call(this, that.$element)
|
|
246
|
+
options.tooltips.init.call(this, that.$element)
|
|
247
247
|
}
|
|
248
|
-
})
|
|
249
|
-
}
|
|
248
|
+
})
|
|
249
|
+
}
|
|
250
250
|
|
|
251
251
|
GraphvizSvg.prototype.setupZoom = function () {
|
|
252
|
-
var that = this
|
|
253
|
-
var $element = this.$element
|
|
254
|
-
var $svg = this.$svg
|
|
252
|
+
var that = this
|
|
253
|
+
var $element = this.$element
|
|
254
|
+
var $svg = this.$svg
|
|
255
255
|
this.zoom = {
|
|
256
256
|
width: $svg.attr("width"),
|
|
257
257
|
height: $svg.attr("height"),
|
|
258
258
|
percentage: null,
|
|
259
|
-
}
|
|
260
|
-
this.scaleView(100.0)
|
|
259
|
+
}
|
|
260
|
+
this.scaleView(100.0)
|
|
261
261
|
$element.mousewheel(function (evt) {
|
|
262
262
|
if (evt.shiftKey) {
|
|
263
|
-
var percentage = that.zoom.percentage
|
|
264
|
-
percentage -= evt.deltaY * evt.deltaFactor
|
|
263
|
+
var percentage = that.zoom.percentage
|
|
264
|
+
percentage -= evt.deltaY * evt.deltaFactor
|
|
265
265
|
if (percentage < 100.0) {
|
|
266
|
-
percentage = 100.0
|
|
266
|
+
percentage = 100.0
|
|
267
267
|
}
|
|
268
268
|
// get pointer offset in view
|
|
269
269
|
// ratio offset within svg
|
|
270
|
-
var dx = evt.pageX - $svg.offset().left
|
|
271
|
-
var dy = evt.pageY - $svg.offset().top
|
|
272
|
-
var rx = dx / $svg.width()
|
|
273
|
-
var ry = dy / $svg.height()
|
|
270
|
+
var dx = evt.pageX - $svg.offset().left
|
|
271
|
+
var dy = evt.pageY - $svg.offset().top
|
|
272
|
+
var rx = dx / $svg.width()
|
|
273
|
+
var ry = dy / $svg.height()
|
|
274
274
|
|
|
275
275
|
// offset within frame ($element)
|
|
276
|
-
var px = evt.pageX - $element.offset().left
|
|
277
|
-
var py = evt.pageY - $element.offset().top
|
|
276
|
+
var px = evt.pageX - $element.offset().left
|
|
277
|
+
var py = evt.pageY - $element.offset().top
|
|
278
278
|
|
|
279
|
-
that.scaleView(percentage)
|
|
279
|
+
that.scaleView(percentage)
|
|
280
280
|
// scroll so pointer is still in same place
|
|
281
|
-
$element.scrollLeft(rx * $svg.width() + 0.5 - px)
|
|
282
|
-
$element.scrollTop(ry * $svg.height() + 0.5 - py)
|
|
283
|
-
return false
|
|
281
|
+
$element.scrollLeft(rx * $svg.width() + 0.5 - px)
|
|
282
|
+
$element.scrollTop(ry * $svg.height() + 0.5 - py)
|
|
283
|
+
return false // stop propogation
|
|
284
284
|
}
|
|
285
|
-
})
|
|
286
|
-
}
|
|
285
|
+
})
|
|
286
|
+
}
|
|
287
287
|
|
|
288
288
|
GraphvizSvg.prototype.scaleView = function (percentage) {
|
|
289
|
-
var that = this
|
|
290
|
-
var $svg = this.$svg
|
|
291
|
-
$svg.attr("width", percentage + "%")
|
|
292
|
-
$svg.attr("height", percentage + "%")
|
|
293
|
-
this.zoom.percentage = percentage
|
|
289
|
+
var that = this
|
|
290
|
+
var $svg = this.$svg
|
|
291
|
+
$svg.attr("width", percentage + "%")
|
|
292
|
+
$svg.attr("height", percentage + "%")
|
|
293
|
+
this.zoom.percentage = percentage
|
|
294
294
|
// now callback to update tooltip position
|
|
295
|
-
var $everything = this.$nodes.add(this.$edges)
|
|
295
|
+
var $everything = this.$nodes.add(this.$edges)
|
|
296
296
|
$everything.children("a[title]").each(function () {
|
|
297
|
-
that.options.tooltips.update.call(this)
|
|
298
|
-
})
|
|
299
|
-
}
|
|
297
|
+
that.options.tooltips.update.call(this)
|
|
298
|
+
})
|
|
299
|
+
}
|
|
300
300
|
|
|
301
301
|
GraphvizSvg.prototype.scaleNode = function ($node) {
|
|
302
|
-
var dx = this.options.shrink.x
|
|
303
|
-
var dy = this.options.shrink.y
|
|
304
|
-
var tagName = $node.prop("tagName")
|
|
302
|
+
var dx = this.options.shrink.x
|
|
303
|
+
var dy = this.options.shrink.y
|
|
304
|
+
var tagName = $node.prop("tagName")
|
|
305
305
|
if (tagName == "ellipse") {
|
|
306
|
-
$node.attr("rx", parseFloat($node.attr("rx")) - dx)
|
|
307
|
-
$node.attr("ry", parseFloat($node.attr("ry")) - dy)
|
|
306
|
+
$node.attr("rx", parseFloat($node.attr("rx")) - dx)
|
|
307
|
+
$node.attr("ry", parseFloat($node.attr("ry")) - dy)
|
|
308
308
|
} else if (tagName == "polygon") {
|
|
309
309
|
// this is more complex - we need to scale it manually
|
|
310
|
-
var bbox = $node[0].getBBox()
|
|
311
|
-
var cx = bbox.x + bbox.width / 2
|
|
312
|
-
var cy = bbox.y + bbox.height / 2
|
|
313
|
-
var pts = $node.attr("points").split(" ")
|
|
314
|
-
var points = ""
|
|
310
|
+
var bbox = $node[0].getBBox()
|
|
311
|
+
var cx = bbox.x + bbox.width / 2
|
|
312
|
+
var cy = bbox.y + bbox.height / 2
|
|
313
|
+
var pts = $node.attr("points").split(" ")
|
|
314
|
+
var points = "" // new value
|
|
315
315
|
for (var i in pts) {
|
|
316
|
-
var xy = pts[i].split(",")
|
|
317
|
-
var ox = parseFloat(xy[0])
|
|
318
|
-
var oy = parseFloat(xy[1])
|
|
316
|
+
var xy = pts[i].split(",")
|
|
317
|
+
var ox = parseFloat(xy[0])
|
|
318
|
+
var oy = parseFloat(xy[1])
|
|
319
319
|
points +=
|
|
320
320
|
((cx - ox) / (bbox.width / 2)) * dx +
|
|
321
321
|
ox +
|
|
322
322
|
"," +
|
|
323
323
|
(((cy - oy) / (bbox.height / 2)) * dy + oy) +
|
|
324
|
-
" "
|
|
324
|
+
" "
|
|
325
325
|
}
|
|
326
|
-
$node.attr("points", points)
|
|
326
|
+
$node.attr("points", points)
|
|
327
327
|
}
|
|
328
|
-
}
|
|
328
|
+
}
|
|
329
329
|
|
|
330
330
|
GraphvizSvg.prototype.ensureEdgeHitArea = function ($edge, padding) {
|
|
331
|
-
var width = parseFloat(padding)
|
|
331
|
+
var width = parseFloat(padding)
|
|
332
332
|
if (!isFinite(width) || width <= 0) {
|
|
333
|
-
return
|
|
333
|
+
return
|
|
334
334
|
}
|
|
335
|
-
var $paths = $edge
|
|
336
|
-
.
|
|
337
|
-
|
|
338
|
-
return $(this).attr("data-graphviz-hitbox") !== "true";
|
|
339
|
-
});
|
|
335
|
+
var $paths = $edge.children("path").filter(function () {
|
|
336
|
+
return $(this).attr("data-graphviz-hitbox") !== "true"
|
|
337
|
+
})
|
|
340
338
|
if (!$paths.length) {
|
|
341
|
-
return
|
|
339
|
+
return
|
|
342
340
|
}
|
|
343
341
|
$paths.each(function () {
|
|
344
|
-
var $path = $(this)
|
|
345
|
-
var $existing = $path.prev('[data-graphviz-hitbox="true"]')
|
|
342
|
+
var $path = $(this)
|
|
343
|
+
var $existing = $path.prev('[data-graphviz-hitbox="true"]')
|
|
346
344
|
if ($existing.length) {
|
|
347
|
-
$existing.attr("stroke-width", width)
|
|
348
|
-
return
|
|
345
|
+
$existing.attr("stroke-width", width)
|
|
346
|
+
return
|
|
349
347
|
}
|
|
350
|
-
var clone = this.cloneNode(false)
|
|
348
|
+
var clone = this.cloneNode(false)
|
|
351
349
|
|
|
352
350
|
/**
|
|
353
351
|
* gtp-5-codex:
|
|
354
|
-
* Cloning the edge paths without copying D3’s data binding caused those Cannot
|
|
355
|
-
* read properties of undefined (reading 'key') errors when d3-graphviz re-rendered.
|
|
356
|
-
* I now copy the original path’s bound datum (__data__) onto the transparent hitbox
|
|
352
|
+
* Cloning the edge paths without copying D3’s data binding caused those Cannot
|
|
353
|
+
* read properties of undefined (reading 'key') errors when d3-graphviz re-rendered.
|
|
354
|
+
* I now copy the original path’s bound datum (__data__) onto the transparent hitbox
|
|
357
355
|
* clone inside ensureEdgeHitArea, so D3 still finds the expected metadata.
|
|
358
356
|
*/
|
|
359
357
|
if (this.__data__) {
|
|
360
|
-
clone.__data__ = this.__data__
|
|
358
|
+
clone.__data__ = this.__data__
|
|
361
359
|
}
|
|
362
360
|
|
|
363
|
-
var $clone = $(clone)
|
|
361
|
+
var $clone = $(clone)
|
|
364
362
|
$clone.attr({
|
|
365
363
|
"data-graphviz-hitbox": "true",
|
|
366
364
|
stroke: "transparent",
|
|
367
365
|
fill: "none",
|
|
368
366
|
"stroke-width": width,
|
|
369
|
-
})
|
|
370
|
-
$clone.attr("pointer-events", "stroke")
|
|
371
|
-
$clone.css("pointer-events", "stroke")
|
|
367
|
+
})
|
|
368
|
+
$clone.attr("pointer-events", "stroke")
|
|
369
|
+
$clone.css("pointer-events", "stroke")
|
|
372
370
|
if (!$clone.attr("stroke-linecap")) {
|
|
373
|
-
$clone.attr("stroke-linecap", $path.attr("stroke-linecap") || "round")
|
|
371
|
+
$clone.attr("stroke-linecap", $path.attr("stroke-linecap") || "round")
|
|
374
372
|
}
|
|
375
|
-
$clone.insertBefore($path)
|
|
376
|
-
})
|
|
377
|
-
}
|
|
373
|
+
$clone.insertBefore($path)
|
|
374
|
+
})
|
|
375
|
+
}
|
|
378
376
|
|
|
379
377
|
GraphvizSvg.prototype.setInteractiveCursor = function ($el, isEdge) {
|
|
380
|
-
$el.css("cursor", "pointer")
|
|
381
|
-
var selectors = "path, polygon, ellipse, rect, text"
|
|
378
|
+
$el.css("cursor", "pointer")
|
|
379
|
+
var selectors = "path, polygon, ellipse, rect, text"
|
|
382
380
|
$el.find(selectors).each(function () {
|
|
383
|
-
$(this).css("cursor", "pointer")
|
|
384
|
-
})
|
|
381
|
+
$(this).css("cursor", "pointer")
|
|
382
|
+
})
|
|
385
383
|
if (isEdge) {
|
|
386
|
-
$el.children('[data-graphviz-hitbox="true"]').css("cursor", "pointer")
|
|
384
|
+
$el.children('[data-graphviz-hitbox="true"]').css("cursor", "pointer")
|
|
387
385
|
}
|
|
388
386
|
$el.find("a").each(function () {
|
|
389
|
-
$(this).css("cursor", "pointer")
|
|
390
|
-
})
|
|
391
|
-
}
|
|
387
|
+
$(this).css("cursor", "pointer")
|
|
388
|
+
})
|
|
389
|
+
}
|
|
392
390
|
|
|
393
391
|
GraphvizSvg.prototype.convertToPx = function (val) {
|
|
394
|
-
var retval = val
|
|
392
|
+
var retval = val
|
|
395
393
|
if (typeof val == "string") {
|
|
396
|
-
var end = val.length
|
|
397
|
-
var factor = 1.0
|
|
394
|
+
var end = val.length
|
|
395
|
+
var factor = 1.0
|
|
398
396
|
if (val.endsWith("px")) {
|
|
399
|
-
end -= 2
|
|
397
|
+
end -= 2
|
|
400
398
|
} else if (val.endsWith("pt")) {
|
|
401
|
-
end -= 2
|
|
402
|
-
factor = GraphvizSvg.GVPT_2_PX
|
|
399
|
+
end -= 2
|
|
400
|
+
factor = GraphvizSvg.GVPT_2_PX
|
|
403
401
|
}
|
|
404
|
-
retval = parseFloat(val.substring(0, end)) * factor
|
|
402
|
+
retval = parseFloat(val.substring(0, end)) * factor
|
|
405
403
|
}
|
|
406
|
-
return retval
|
|
407
|
-
}
|
|
404
|
+
return retval
|
|
405
|
+
}
|
|
408
406
|
|
|
409
407
|
GraphvizSvg.prototype.findEdge = function (nodeName, testEdge, $retval) {
|
|
410
|
-
var retval = []
|
|
408
|
+
var retval = []
|
|
411
409
|
for (var name in this._edgesByName) {
|
|
412
|
-
var match = testEdge(nodeName, name)
|
|
410
|
+
var match = testEdge(nodeName, name)
|
|
413
411
|
if (match) {
|
|
414
412
|
if ($retval) {
|
|
415
413
|
this._edgesByName[name].forEach((edge) => {
|
|
416
|
-
$retval.push(edge)
|
|
417
|
-
})
|
|
414
|
+
$retval.push(edge)
|
|
415
|
+
})
|
|
418
416
|
}
|
|
419
|
-
retval.push(match)
|
|
417
|
+
retval.push(match)
|
|
420
418
|
}
|
|
421
419
|
}
|
|
422
|
-
return retval
|
|
423
|
-
}
|
|
424
|
-
|
|
425
|
-
GraphvizSvg.prototype.findLinked = function (
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
$retval
|
|
430
|
-
) {
|
|
431
|
-
var that = this;
|
|
432
|
-
var $node = $(node);
|
|
433
|
-
var $edges = null;
|
|
420
|
+
return retval
|
|
421
|
+
}
|
|
422
|
+
|
|
423
|
+
GraphvizSvg.prototype.findLinked = function (node, includeEdges, testEdge, $retval) {
|
|
424
|
+
var that = this
|
|
425
|
+
var $node = $(node)
|
|
426
|
+
var $edges = null
|
|
434
427
|
if (includeEdges) {
|
|
435
|
-
$edges = $retval
|
|
428
|
+
$edges = $retval
|
|
436
429
|
}
|
|
437
|
-
var names = this.findEdge($node.attr("data-name"), testEdge, $edges)
|
|
430
|
+
var names = this.findEdge($node.attr("data-name"), testEdge, $edges)
|
|
438
431
|
for (var i in names) {
|
|
439
|
-
var n = this._nodesByName[names[i]]
|
|
432
|
+
var n = this._nodesByName[names[i]]
|
|
440
433
|
if (!$retval.is(n)) {
|
|
441
|
-
$retval.push(n)
|
|
442
|
-
that.findLinked(n, includeEdges, testEdge, $retval)
|
|
434
|
+
$retval.push(n)
|
|
435
|
+
that.findLinked(n, includeEdges, testEdge, $retval)
|
|
443
436
|
}
|
|
444
437
|
}
|
|
445
|
-
}
|
|
438
|
+
}
|
|
446
439
|
|
|
447
440
|
GraphvizSvg.prototype.colorElement = function ($el, getColor) {
|
|
448
|
-
var bg = this.$element.css("background")
|
|
441
|
+
var bg = this.$element.css("background")
|
|
449
442
|
$el.find("polygon, ellipse, path").each(function () {
|
|
450
|
-
var $this = $(this)
|
|
443
|
+
var $this = $(this)
|
|
451
444
|
if ($this.attr("data-graphviz-hitbox") === "true") {
|
|
452
|
-
return
|
|
445
|
+
return
|
|
453
446
|
}
|
|
454
|
-
var color = $this.data("graphviz.svg.color")
|
|
447
|
+
var color = $this.data("graphviz.svg.color")
|
|
455
448
|
if (color.fill && color.fill != "none") {
|
|
456
|
-
$this.attr("fill", getColor(color.fill, bg))
|
|
449
|
+
$this.attr("fill", getColor(color.fill, bg)) // don't set fill if it's a path
|
|
457
450
|
}
|
|
458
451
|
if (color.stroke && color.stroke != "none") {
|
|
459
|
-
$this.attr("stroke", getColor(color.stroke, bg))
|
|
452
|
+
$this.attr("stroke", getColor(color.stroke, bg))
|
|
460
453
|
}
|
|
461
|
-
$this.attr(
|
|
462
|
-
})
|
|
463
|
-
}
|
|
454
|
+
$this.attr("stroke-width", 1.6)
|
|
455
|
+
})
|
|
456
|
+
}
|
|
464
457
|
|
|
465
458
|
GraphvizSvg.prototype.restoreElement = function ($el) {
|
|
466
459
|
$el.find("polygon, ellipse, path").each(function () {
|
|
467
|
-
var $this = $(this)
|
|
460
|
+
var $this = $(this)
|
|
468
461
|
if ($this.attr("data-graphviz-hitbox") === "true") {
|
|
469
|
-
return
|
|
462
|
+
return
|
|
470
463
|
}
|
|
471
|
-
var color = $this.data("graphviz.svg.color")
|
|
464
|
+
var color = $this.data("graphviz.svg.color")
|
|
472
465
|
if (color.fill && color.fill != "none") {
|
|
473
|
-
$this.attr("fill", color.fill)
|
|
466
|
+
$this.attr("fill", color.fill) // don't set fill if it's a path
|
|
474
467
|
}
|
|
475
468
|
if (color.stroke && color.stroke != "none") {
|
|
476
|
-
$this.attr("stroke", color.stroke)
|
|
469
|
+
$this.attr("stroke", color.stroke)
|
|
477
470
|
}
|
|
478
|
-
$this.attr(
|
|
479
|
-
})
|
|
480
|
-
}
|
|
471
|
+
$this.attr("stroke-width", 1)
|
|
472
|
+
})
|
|
473
|
+
}
|
|
481
474
|
|
|
482
475
|
// methods users can actually call
|
|
483
476
|
GraphvizSvg.prototype.nodes = function () {
|
|
484
|
-
return this.$nodes
|
|
485
|
-
}
|
|
477
|
+
return this.$nodes
|
|
478
|
+
}
|
|
486
479
|
|
|
487
480
|
GraphvizSvg.prototype.edges = function () {
|
|
488
|
-
return this.$edges
|
|
489
|
-
}
|
|
481
|
+
return this.$edges
|
|
482
|
+
}
|
|
490
483
|
|
|
491
484
|
GraphvizSvg.prototype.clusters = function () {
|
|
492
|
-
return this.$clusters
|
|
493
|
-
}
|
|
485
|
+
return this.$clusters
|
|
486
|
+
}
|
|
494
487
|
|
|
495
488
|
GraphvizSvg.prototype.nodesByName = function () {
|
|
496
|
-
return this._nodesByName
|
|
497
|
-
}
|
|
489
|
+
return this._nodesByName
|
|
490
|
+
}
|
|
498
491
|
|
|
499
492
|
GraphvizSvg.prototype.edgesByName = function () {
|
|
500
|
-
return this._edgesByName
|
|
501
|
-
}
|
|
493
|
+
return this._edgesByName
|
|
494
|
+
}
|
|
502
495
|
|
|
503
496
|
GraphvizSvg.prototype.clustersByName = function () {
|
|
504
|
-
return this._clustersByName
|
|
505
|
-
}
|
|
497
|
+
return this._clustersByName
|
|
498
|
+
}
|
|
506
499
|
|
|
507
500
|
GraphvizSvg.prototype.linkedTo = function (node, includeEdges) {
|
|
508
|
-
var $retval = $()
|
|
501
|
+
var $retval = $()
|
|
509
502
|
this.findLinked(
|
|
510
503
|
node,
|
|
511
504
|
includeEdges,
|
|
512
505
|
function (nodeName, edgeName) {
|
|
513
|
-
var other = null
|
|
506
|
+
var other = null
|
|
514
507
|
|
|
515
|
-
const connection = edgeName.split("->")
|
|
508
|
+
const connection = edgeName.split("->")
|
|
516
509
|
if (
|
|
517
510
|
connection.length > 1 &&
|
|
518
|
-
(connection[1] === nodeName ||
|
|
519
|
-
connection[1].startsWith(nodeName + ":"))
|
|
511
|
+
(connection[1] === nodeName || connection[1].startsWith(nodeName + ":"))
|
|
520
512
|
) {
|
|
521
|
-
return connection[0].split(":")[0]
|
|
513
|
+
return connection[0].split(":")[0]
|
|
522
514
|
}
|
|
523
515
|
|
|
524
|
-
return other
|
|
516
|
+
return other
|
|
525
517
|
},
|
|
526
518
|
$retval
|
|
527
|
-
)
|
|
528
|
-
return $retval
|
|
529
|
-
}
|
|
519
|
+
)
|
|
520
|
+
return $retval
|
|
521
|
+
}
|
|
530
522
|
|
|
531
523
|
GraphvizSvg.prototype.linkedFrom = function (node, includeEdges) {
|
|
532
|
-
var $retval = $()
|
|
524
|
+
var $retval = $()
|
|
533
525
|
this.findLinked(
|
|
534
526
|
node,
|
|
535
527
|
includeEdges,
|
|
536
528
|
function (nodeName, edgeName) {
|
|
537
|
-
var other = null
|
|
529
|
+
var other = null
|
|
538
530
|
|
|
539
|
-
const connection = edgeName.split("->")
|
|
531
|
+
const connection = edgeName.split("->")
|
|
540
532
|
if (
|
|
541
533
|
connection.length > 1 &&
|
|
542
|
-
(connection[0] === nodeName ||
|
|
543
|
-
connection[0].startsWith(nodeName + ":"))
|
|
534
|
+
(connection[0] === nodeName || connection[0].startsWith(nodeName + ":"))
|
|
544
535
|
) {
|
|
545
|
-
return connection[1].split(":")[0]
|
|
536
|
+
return connection[1].split(":")[0]
|
|
546
537
|
}
|
|
547
|
-
return other
|
|
538
|
+
return other
|
|
548
539
|
},
|
|
549
540
|
$retval
|
|
550
|
-
)
|
|
551
|
-
return $retval
|
|
552
|
-
}
|
|
541
|
+
)
|
|
542
|
+
return $retval
|
|
543
|
+
}
|
|
553
544
|
|
|
554
545
|
GraphvizSvg.prototype.linked = function (node, includeEdges) {
|
|
555
|
-
var $retval = $()
|
|
546
|
+
var $retval = $()
|
|
556
547
|
this.findLinked(
|
|
557
548
|
node,
|
|
558
549
|
includeEdges,
|
|
559
550
|
function (nodeName, edgeName) {
|
|
560
|
-
return "^" + name + "--(.*)$"
|
|
551
|
+
return "^" + name + "--(.*)$"
|
|
561
552
|
},
|
|
562
553
|
$retval
|
|
563
|
-
)
|
|
554
|
+
)
|
|
564
555
|
this.findLinked(
|
|
565
556
|
node,
|
|
566
557
|
includeEdges,
|
|
567
558
|
function (nodeName, edgeName) {
|
|
568
|
-
return "^(.*)--" + name + "$"
|
|
559
|
+
return "^(.*)--" + name + "$"
|
|
569
560
|
},
|
|
570
561
|
$retval
|
|
571
|
-
)
|
|
572
|
-
return $retval
|
|
573
|
-
}
|
|
562
|
+
)
|
|
563
|
+
return $retval
|
|
564
|
+
}
|
|
574
565
|
|
|
575
566
|
GraphvizSvg.prototype.tooltip = function ($elements, show) {
|
|
576
|
-
var that = this
|
|
577
|
-
var options = this.options
|
|
567
|
+
var that = this
|
|
568
|
+
var options = this.options
|
|
578
569
|
$elements.each(function () {
|
|
579
570
|
$(this)
|
|
580
571
|
.find("a[title]")
|
|
581
572
|
.each(function () {
|
|
582
573
|
if (show) {
|
|
583
|
-
options.tooltips.show.call(this)
|
|
574
|
+
options.tooltips.show.call(this)
|
|
584
575
|
} else {
|
|
585
|
-
options.tooltips.hide.call(this)
|
|
576
|
+
options.tooltips.hide.call(this)
|
|
586
577
|
}
|
|
587
|
-
})
|
|
588
|
-
})
|
|
589
|
-
}
|
|
578
|
+
})
|
|
579
|
+
})
|
|
580
|
+
}
|
|
590
581
|
|
|
591
582
|
GraphvizSvg.prototype.bringToFront = function ($elements) {
|
|
592
|
-
$elements.detach().appendTo(this.$graph)
|
|
593
|
-
}
|
|
583
|
+
$elements.detach().appendTo(this.$graph)
|
|
584
|
+
}
|
|
594
585
|
|
|
595
586
|
GraphvizSvg.prototype.sendToBack = function ($elements) {
|
|
596
587
|
if (this.$background.length) {
|
|
597
|
-
$element.insertAfter(this.$background)
|
|
588
|
+
$element.insertAfter(this.$background)
|
|
598
589
|
} else {
|
|
599
|
-
$elements.detach().prependTo(this.$graph)
|
|
590
|
+
$elements.detach().prependTo(this.$graph)
|
|
600
591
|
}
|
|
601
|
-
}
|
|
592
|
+
}
|
|
602
593
|
|
|
603
594
|
GraphvizSvg.prototype.highlight = function ($nodesEdges, tooltips) {
|
|
604
|
-
var that = this
|
|
605
|
-
var options = this.options
|
|
606
|
-
var $everything = this.$nodes.add(this.$edges).add(this.$clusters)
|
|
595
|
+
var that = this
|
|
596
|
+
var options = this.options
|
|
597
|
+
var $everything = this.$nodes.add(this.$edges).add(this.$clusters)
|
|
607
598
|
if ($nodesEdges && $nodesEdges.length > 0) {
|
|
608
599
|
// create set of all other elements and dim them
|
|
609
600
|
$everything.not($nodesEdges).each(function () {
|
|
610
|
-
that.colorElement($(this), options.highlight.unselected)
|
|
611
|
-
that.tooltip($(this))
|
|
612
|
-
})
|
|
601
|
+
that.colorElement($(this), options.highlight.unselected)
|
|
602
|
+
that.tooltip($(this))
|
|
603
|
+
})
|
|
613
604
|
$nodesEdges.each(function () {
|
|
614
|
-
that.colorElement($(this), options.highlight.selected)
|
|
615
|
-
})
|
|
605
|
+
that.colorElement($(this), options.highlight.selected)
|
|
606
|
+
})
|
|
616
607
|
if (tooltips) {
|
|
617
|
-
this.tooltip($nodesEdges, true)
|
|
608
|
+
this.tooltip($nodesEdges, true)
|
|
618
609
|
}
|
|
619
610
|
} else {
|
|
620
611
|
$everything.each(function () {
|
|
621
|
-
that.restoreElement($(this))
|
|
622
|
-
})
|
|
623
|
-
this.tooltip($everything)
|
|
612
|
+
that.restoreElement($(this))
|
|
613
|
+
})
|
|
614
|
+
this.tooltip($everything)
|
|
624
615
|
}
|
|
625
|
-
}
|
|
616
|
+
}
|
|
626
617
|
|
|
627
618
|
GraphvizSvg.prototype.destroy = function () {
|
|
628
|
-
var that = this
|
|
619
|
+
var that = this
|
|
629
620
|
this.hide(function () {
|
|
630
|
-
that.$element.off("." + that.type).removeData(that.type)
|
|
631
|
-
})
|
|
632
|
-
}
|
|
621
|
+
that.$element.off("." + that.type).removeData(that.type)
|
|
622
|
+
})
|
|
623
|
+
}
|
|
633
624
|
|
|
634
625
|
// GRAPHVIZSVG PLUGIN DEFINITION
|
|
635
626
|
// =============================
|
|
636
627
|
|
|
637
628
|
function Plugin(option) {
|
|
638
629
|
return this.each(function () {
|
|
639
|
-
var $this = $(this)
|
|
640
|
-
var data = $this.data("graphviz.svg")
|
|
641
|
-
var options = typeof option == "object" && option
|
|
642
|
-
|
|
643
|
-
if (!data && /destroy/.test(option)) return
|
|
644
|
-
if (!data)
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
});
|
|
630
|
+
var $this = $(this)
|
|
631
|
+
var data = $this.data("graphviz.svg")
|
|
632
|
+
var options = typeof option == "object" && option
|
|
633
|
+
|
|
634
|
+
if (!data && /destroy/.test(option)) return
|
|
635
|
+
if (!data) $this.data("graphviz.svg", (data = new GraphvizSvg(this, options)))
|
|
636
|
+
if (typeof option == "string") data[option]()
|
|
637
|
+
})
|
|
648
638
|
}
|
|
649
639
|
|
|
650
|
-
var old = $.fn.graphviz
|
|
640
|
+
var old = $.fn.graphviz
|
|
651
641
|
|
|
652
|
-
$.fn.graphviz = Plugin
|
|
653
|
-
$.fn.graphviz.Constructor = GraphvizSvg
|
|
642
|
+
$.fn.graphviz = Plugin
|
|
643
|
+
$.fn.graphviz.Constructor = GraphvizSvg
|
|
654
644
|
|
|
655
645
|
// GRAPHVIZ NO CONFLICT
|
|
656
646
|
// ====================
|
|
657
647
|
|
|
658
648
|
$.fn.graphviz.noConflict = function () {
|
|
659
|
-
$.fn.graphviz = old
|
|
660
|
-
return this
|
|
661
|
-
}
|
|
662
|
-
})(jQuery)
|
|
649
|
+
$.fn.graphviz = old
|
|
650
|
+
return this
|
|
651
|
+
}
|
|
652
|
+
})(jQuery)
|