Related
Given a stacked bar plot, how can I add labels with the values of each of the bar?
Below is an example of what I'm trying to do:
You can do this by layering a bar mark and a text mark. For example (open in editor):
{
"data": {"url": "data/barley.json"},
"width": 400,
"encoding": {
"x": {
"type": "quantitative",
"aggregate": "sum",
"field": "yield",
"stack": "zero"
},
"y": {"type": "nominal", "field": "variety"}
},
"layer": [
{
"mark": "bar",
"encoding": {"color": {"type": "nominal", "field": "site"}}
},
{
"mark": {"type": "text", "color": "white", "dx": -15, "dy": 3},
"encoding": {
"detail": {"type": "nominal", "field": "site"},
"text": {
"type": "quantitative",
"aggregate": "sum",
"field": "yield",
"format": ".1f"
}
}
}
]
}
I've created a plot using Vega-Lite that allows me to use a binder to alter the parameters of a functions that I'm visualizing. It's similar to this sample code:
{
"$schema": "https://vega.github.io/schema/vega-lite/v4.json",
"description": "Plots two functions using a generated sequence.",
"width": 300,
"height": 150,
"data": {"sequence": {"start": 0, "stop": 12.7, "step": 0.1, "as": "x"}},
"transform": [
{"calculate": "amp.sin * sin(datum.x)", "as": "sin(x)"},
{"calculate": "amp.cos * cos(datum.x)", "as": "cos(x)"},
{"fold": ["sin(x)", "cos(x)"]}
],
"mark": "line",
"encoding": {
"x": {"type": "quantitative", "field": "x"},
"y": {"field": "value", "type": "quantitative"},
"color": {"field": "key", "type": "nominal", "title": null}
},
"selection": {
"amp": {
"type": "single",
"fields": ["sin", "cos"],
"init": {"sin": 1, "cos": 1},
"bind": {
"sin": {"input": "range", "min": 0, "max": 10, "step": 0.1},
"cos": {"input": "range", "min": 0, "max": 10, "step": 0.1}
}
}
}
}
Here is the code above in the Vega editor.
Now, what I'd like to do is to create another visualization parallel to this one, but with another function, but that would also vary with the same binder.
Is this possible? Note that in my code, each plot uses a different dataset, but share the variable of the binder in common.
Yes, for example you can do this using a "concat". Here is an example based on your chart (open in editor):
{
"$schema": "https://vega.github.io/schema/vega-lite/v4.json",
"description": "Plots two functions using a generated sequence.",
"data": {"sequence": {"start": 0, "stop": 12.7, "step": 0.1, "as": "x"}},
"concat": [
{
"width": 300,
"height": 150,
"transform": [
{"calculate": "amp.sin * sin(datum.x)", "as": "sin(x)"},
{"calculate": "amp.cos * cos(datum.x)", "as": "cos(x)"},
{"fold": ["sin(x)", "cos(x)"]}
],
"mark": "line",
"encoding": {
"x": {"type": "quantitative", "field": "x"},
"y": {"field": "value", "type": "quantitative"},
"color": {"field": "key", "type": "nominal", "title": null}
},
"selection": {
"amp": {
"type": "single",
"fields": ["sin", "cos"],
"init": {"sin": 1, "cos": 1},
"bind": {
"sin": {"input": "range", "min": 0, "max": 10, "step": 0.1},
"cos": {"input": "range", "min": 0, "max": 10, "step": 0.1}
}
}
}
},
{
"width": 300,
"height": 150,
"transform": [
{
"calculate": "amp.cos * cos(datum.x) - amp.sin * sin(datum.x)",
"as": "cos(x) - sin(x)"
}
],
"mark": "line",
"encoding": {
"x": {"type": "quantitative", "field": "x"},
"y": {"field": "cos(x) - sin(x)", "type": "quantitative"}
}
}
],
"resolve": {"scale": {"y": "shared", "color": "independent"}}
}
How do I write a CosmosDB query or SPR that allows me to look for an entry in all entries in an array? where each array entry is a complex datatype and not just a simple array?
I have tried using this query:
SELECT DISTINCT c.locales[0].categories[0] AS topLevelCategory
FROM c
WHERE c.locales[0].country = 'SE'
The problem is that I cannot gurantee that c.loclales[0] is always 'SE' some times that is the second or third entry in the array so I dont know what c.locales[X] should be where X represents the locale I need, for example if c.locales[0] is 'SE' then I wont get the hit I want because 'SE' happens to be c.locales[1]
How can get around this limitation? I need to be able to first apply the country = 'SE' to get the correct array entry and then after that get the categories from that array entry.
I just cannot figure out how this can be done?
Sample document below and expected output would be
"Herr" in whatever output format is easiest.
{
"id": "0570eca0-8f16-4c85-a985-e3a271bcc6bc",
"_id": "5b07c2bfbc7407000122e8b4",
"artno": "0614460008",
"vendor": "Acme",
"updatedAt": "2019-06-25T18:50:33.167Z",
"locales": [
{
"title": "Gestreiftes T-Shirt",
"description": "Gestreiftes T-Shirt aus Baumwolljersey.",
"categories": [
"Herren",
"Große Größen",
"T-Shirts & Tanktops",
"T-Shirt"
],
"brand": null,
"images": [
],
"country": "DE",
"currency": "EUR",
"language": "de",
"variants": [
{
"artno": "0614460008005",
"urls": [
],
"price": 9.99,
"stock": 1,
"attributes": {
"size": "XL",
"color": "Schwarz/Weiß gestreift"
}
},
{
"artno": "0614460008002",
"urls": [
],
"price": 9.99,
"stock": 1,
"attributes": {
"size": "S",
"color": "Schwarz/Weiß gestreift"
}
},
{
"artno": "0614460008004",
"urls": [
],
"price": 9.99,
"stock": 1,
"attributes": {
"size": "L",
"color": "Schwarz/Weiß gestreift"
}
},
{
"artno": "0614460008001",
"urls": [
],
"price": 9.99,
"stock": 1,
"attributes": {
"size": "XS",
"color": "Schwarz/Weiß gestreift"
}
},
{
"artno": "0614460008006",
"urls": [
],
"price": 9.99,
"stock": 1,
"attributes": {
"size": "XXL",
"color": "Schwarz/Weiß gestreift"
}
},
{
"artno": "0614460008003",
"urls": [
],
"price": 9.99,
"stock": 1,
"attributes": {
"size": "M",
"color": "Schwarz/Weiß gestreift"
}
}
]
},
{
"title": "Striped T-shirt",
"description": "Striped T-shirt in cotton jersey.",
"categories": [
"Men",
"T-shirts & Vests",
"Short Sleeve",
"T-shirt"
],
"brand": null,
"images": [
],
"country": "UK",
"currency": "GBP",
"language": "en",
"variants": [
{
"artno": "0614460008006",
"urls": [
],
"price": 8.99,
"stock": 1,
"attributes": {
"size": "XXL",
"color": "Black/White striped"
}
},
{
"artno": "0614460008005",
"urls": [
],
"price": 8.99,
"stock": 1,
"attributes": {
"size": "XL",
"color": "Black/White striped"
}
},
{
"artno": "0614460008004",
"urls": [
],
"price": 8.99,
"stock": 1,
"attributes": {
"size": "L",
"color": "Black/White striped"
}
},
{
"artno": "0614460008002",
"urls": [
],
"price": 8.99,
"stock": 1,
"attributes": {
"size": "S",
"color": "Black/White striped"
}
},
{
"artno": "0614460008003",
"urls": [
],
"price": 8.99,
"stock": 1,
"attributes": {
"size": "M",
"color": "Black/White striped"
}
},
{
"artno": "0614460008001",
"urls": [
],
"price": 8.99,
"stock": 1,
"attributes": {
"size": "XS",
"color": "Black/White striped"
}
}
]
},
{
"title": "Randig t-shirt",
"description": "En randig t-shirt i bomullstrikå.",
"categories": [
"Herr",
"T-shirts & Linnen",
"Kortärmat",
"T-shirt"
],
"brand": null,
"images": [
],
"country": "SE",
"currency": "SEK",
"language": "sv",
"variants": [
{
"artno": "0614460008001",
"urls": [
],
"price": 99,
"stock": 1,
"attributes": {
"size": "XS",
"color": "Svart/Vitrandig"
}
},
{
"artno": "0614460008001",
"urls": [
],
"price": 99,
"stock": 1,
"attributes": {
"size": "XL",
"color": "Svart/Vitrandig"
}
},
{
"artno": "0614460008001",
"urls": [
],
"price": 99,
"stock": 1,
"attributes": {
"size": "S",
"color": "Svart/Vitrandig"
}
},
{
"artno": "0614460008001",
"urls": [
],
"price": 99,
"stock": 1,
"attributes": {
"size": "XXL",
"color": "Svart/Vitrandig"
}
},
{
"artno": "0614460008001",
"urls": [
],
"price": 99,
"stock": 1,
"attributes": {
"size": "M",
"color": "Svart/Vitrandig"
}
},
{
"artno": "0614460008001",
"urls": [
],
"price": 99,
"stock": 1,
"attributes": {
"size": "L",
"color": "Svart/Vitrandig"
}
}
]
},
{
"title": "Striped T-shirt",
"description": "Striped T-shirt in cotton jersey.",
"categories": [
"Men",
"T-shirts & Tank tops",
"Short Sleeves",
"T-shirt"
],
"brand": null,
"images": [
],
"country": "US",
"currency": "USD",
"language": "en",
"variants": [
{
"artno": "0614460008001",
"urls": [
],
"price": 9.99,
"stock": 0,
"attributes": {
"size": "S",
"color": "Black/white striped"
}
},
{
"artno": "0614460008001",
"urls": [
],
"price": 9.99,
"stock": 0,
"attributes": {
"size": "XL",
"color": "Black/white striped"
}
},
{
"artno": "0614460008001",
"urls": [
],
"price": 9.99,
"stock": 0,
"attributes": {
"size": "M",
"color": "Black/white striped"
}
},
{
"artno": "0614460008001",
"urls": [
],
"price": 9.99,
"stock": 0,
"attributes": {
"size": "L",
"color": "Black/white striped"
}
},
{
"artno": "0614460008001",
"urls": [
],
"price": 9.99,
"stock": 0,
"attributes": {
"size": "XXL",
"color": "Black/white striped"
}
},
{
"artno": "0614460008001",
"urls": [
],
"price": 9.99,
"stock": 1,
"attributes": {
"size": "XS",
"color": "Black/white striped"
}
}
]
}
],
"relatedArtno": [
"0614460001",
"0614460002",
"0614460005",
"0614460006",
"0614460007",
"0614460011",
"0614460012"
],
"_rid": "QEwcAMCVWqgGAAAAAAAAAA==",
"_self": "dbs/QEwcAA==/colls/QEwcAMCVWqg=/docs/QEwcAMCVWqgGAAAAAAAAAA==/",
"_etag": "\"2e00f1ca-0000-0c00-0000-5d144d660000\"",
"_attachments": "attachments/",
"_ts": 1561611622
}
Use Join in your sql:
SELECT locales.categories[0] AS topLevelCategory
FROM c
join locales in c.locales
WHERE locales.country = 'SE'
Output:
Update Answer:
Two points.
One,your locales is also an array so you can't access categories with c.locales.categories.You need to query categories using c.locales[index].categories.
Two,Array_contains has third param. If you want to filter array with partial conditions,you need to add third param as false.
ARRAY_CONTAINS(c.locales[index].categories[0], 'kids',true)
More details,please refer to the document.
I have a query that
SELECT c
FROM c
join locales in c.locales
WHERE locales.country = 'SE' AND
locales.language = 'sv' AND
locales.categories[0] = 'Dam'
I am trying to adjust it to only display the relevant locale as specified in the WHERE clause so I tried adjusting it to:
SELECT c.locales[0]
FROM c
join locales in c.locales
WHERE locales.country = 'SE' AND
locales.language = 'sv' AND
locales.categories[0] = 'Dam'
But that does not help since it might not be locales[0], I had assumed that the join would make the relevant part of the array always appear as index [0] but I was wrong
How can I adjust the query to show the entire document but only the relevant part in the locales array?
Please note I want the entire document shown but only with the relevant locale from that array.
The documents looks as below:
{
"id": "0570eca0-8f16-4c85-a985-e3a271bcc6bc",
"_id": "5b07c2bfbc7407000122e8b4",
"artno": "0614460008",
"vendor": "Acme",
"updatedAt": "2019-06-25T18:50:33.167Z",
"locales": [
{
"title": "Gestreiftes T-Shirt",
"description": "Gestreiftes T-Shirt aus Baumwolljersey.",
"categories": [
"Herren",
"Große Größen",
"T-Shirts & Tanktops",
"T-Shirt"
],
"brand": null,
"images": [
],
"country": "DE",
"currency": "EUR",
"language": "de",
"variants": [
{
"artno": "0614460008005",
"urls": [
],
"price": 9.99,
"stock": 1,
"attributes": {
"size": "XL",
"color": "Schwarz/Weiß gestreift"
}
},
{
"artno": "0614460008002",
"urls": [
],
"price": 9.99,
"stock": 1,
"attributes": {
"size": "S",
"color": "Schwarz/Weiß gestreift"
}
},
{
"artno": "0614460008004",
"urls": [
],
"price": 9.99,
"stock": 1,
"attributes": {
"size": "L",
"color": "Schwarz/Weiß gestreift"
}
},
{
"artno": "0614460008001",
"urls": [
],
"price": 9.99,
"stock": 1,
"attributes": {
"size": "XS",
"color": "Schwarz/Weiß gestreift"
}
},
{
"artno": "0614460008006",
"urls": [
],
"price": 9.99,
"stock": 1,
"attributes": {
"size": "XXL",
"color": "Schwarz/Weiß gestreift"
}
},
{
"artno": "0614460008003",
"urls": [
],
"price": 9.99,
"stock": 1,
"attributes": {
"size": "M",
"color": "Schwarz/Weiß gestreift"
}
}
]
},
{
"title": "Striped T-shirt",
"description": "Striped T-shirt in cotton jersey.",
"categories": [
"Men",
"T-shirts & Vests",
"Short Sleeve",
"T-shirt"
],
"brand": null,
"images": [
],
"country": "UK",
"currency": "GBP",
"language": "en",
"variants": [
{
"artno": "0614460008006",
"urls": [
],
"price": 8.99,
"stock": 1,
"attributes": {
"size": "XXL",
"color": "Black/White striped"
}
},
{
"artno": "0614460008005",
"urls": [
],
"price": 8.99,
"stock": 1,
"attributes": {
"size": "XL",
"color": "Black/White striped"
}
},
{
"artno": "0614460008004",
"urls": [
],
"price": 8.99,
"stock": 1,
"attributes": {
"size": "L",
"color": "Black/White striped"
}
},
{
"artno": "0614460008002",
"urls": [
],
"price": 8.99,
"stock": 1,
"attributes": {
"size": "S",
"color": "Black/White striped"
}
},
{
"artno": "0614460008003",
"urls": [
],
"price": 8.99,
"stock": 1,
"attributes": {
"size": "M",
"color": "Black/White striped"
}
},
{
"artno": "0614460008001",
"urls": [
],
"price": 8.99,
"stock": 1,
"attributes": {
"size": "XS",
"color": "Black/White striped"
}
}
]
},
{
"title": "Randig t-shirt",
"description": "En randig t-shirt i bomullstrikå.",
"categories": [
"Herr",
"T-shirts & Linnen",
"Kortärmat",
"T-shirt"
],
"brand": null,
"images": [
],
"country": "SE",
"currency": "SEK",
"language": "sv",
"variants": [
{
"artno": "0614460008001",
"urls": [
],
"price": 99,
"stock": 1,
"attributes": {
"size": "XS",
"color": "Svart/Vitrandig"
}
},
{
"artno": "0614460008001",
"urls": [
],
"price": 99,
"stock": 1,
"attributes": {
"size": "XL",
"color": "Svart/Vitrandig"
}
},
{
"artno": "0614460008001",
"urls": [
],
"price": 99,
"stock": 1,
"attributes": {
"size": "S",
"color": "Svart/Vitrandig"
}
},
{
"artno": "0614460008001",
"urls": [
],
"price": 99,
"stock": 1,
"attributes": {
"size": "XXL",
"color": "Svart/Vitrandig"
}
},
{
"artno": "0614460008001",
"urls": [
],
"price": 99,
"stock": 1,
"attributes": {
"size": "M",
"color": "Svart/Vitrandig"
}
},
{
"artno": "0614460008001",
"urls": [
],
"price": 99,
"stock": 1,
"attributes": {
"size": "L",
"color": "Svart/Vitrandig"
}
}
]
},
{
"title": "Striped T-shirt",
"description": "Striped T-shirt in cotton jersey.",
"categories": [
"Men",
"T-shirts & Tank tops",
"Short Sleeves",
"T-shirt"
],
"brand": null,
"images": [
],
"country": "US",
"currency": "USD",
"language": "en",
"variants": [
{
"artno": "0614460008001",
"urls": [
],
"price": 9.99,
"stock": 0,
"attributes": {
"size": "S",
"color": "Black/white striped"
}
},
{
"artno": "0614460008001",
"urls": [
],
"price": 9.99,
"stock": 0,
"attributes": {
"size": "XL",
"color": "Black/white striped"
}
},
{
"artno": "0614460008001",
"urls": [
],
"price": 9.99,
"stock": 0,
"attributes": {
"size": "M",
"color": "Black/white striped"
}
},
{
"artno": "0614460008001",
"urls": [
],
"price": 9.99,
"stock": 0,
"attributes": {
"size": "L",
"color": "Black/white striped"
}
},
{
"artno": "0614460008001",
"urls": [
],
"price": 9.99,
"stock": 0,
"attributes": {
"size": "XXL",
"color": "Black/white striped"
}
},
{
"artno": "0614460008001",
"urls": [
],
"price": 9.99,
"stock": 1,
"attributes": {
"size": "XS",
"color": "Black/white striped"
}
}
]
}
],
"relatedArtno": [
"0614460001",
"0614460002",
"0614460005",
"0614460006",
"0614460007",
"0614460011",
"0614460012"
],
"_rid": "QEwcAMCVWqgGAAAAAAAAAA==",
"_self": "dbs/QEwcAA==/colls/QEwcAMCVWqg=/docs/QEwcAMCVWqgGAAAAAAAAAA==/",
"_etag": "\"2e00f1ca-0000-0c00-0000-5d144d660000\"",
"_attachments": "attachments/",
"_ts": 1561611622
}
Matt. According to your description, i think you could make a slight change as below:
SELECT locales
FROM c
join locales in c.locales
WHERE locales.country = 'SE' AND
locales.language = 'sv' AND
locales.categories[0] = 'Herr'
Output:
Update sql:
SELECT c.id,c.artno,c.XXX(what properties you want),.....
,locales
FROM c
join locales in c.locales
WHERE locales.country = 'SE' AND
locales.language = 'sv' AND
locales.categories[0] = 'Herr'
Trying to transcript audio from Telegram voice message but I got "unable to transcode data stream audio/opus -> audio/x-float-array" error from watson's speech to text node.
I'm using Node-Red on Raspberry to simply transcript audio from Telegram voice message with node-red-contrib-telegrambot and node-red-node-watson.
With text messages, my code works as a charm.
With Voice Messages, I got "unable to transcode data stream audio/opus -> audio/x-float-array" error from watson's speech to text node.
node-red flow images I don't have enough reputation point to post images :(
JSON flow export
[
{
"id": "b4106ec1.63dd58",
"type": "tab",
"label": "Telegram",
"disabled": false,
"info": ""
},
{
"id": "d1198164.e38f68",
"type": "telegram receiver",
"z": "b4106ec1.63dd58",
"name": "FMWatsonBot",
"bot": "5f347711.7876d8",
"saveDataDir": "",
"x": 110,
"y": 100,
"wires": [
[
"f4b4ab25.5dde18",
"f5d126df.5b6928"
],
[]
]
},
{
"id": "c6ec445d.0840d8",
"type": "telegram sender",
"z": "b4106ec1.63dd58",
"name": "Send2Telegram",
"bot": "5f347711.7876d8",
"x": 780,
"y": 80,
"wires": [
[]
]
},
{
"id": "f4b4ab25.5dde18",
"type": "debug",
"z": "b4106ec1.63dd58",
"name": "",
"active": true,
"tosidebar": true,
"console": false,
"tostatus": false,
"complete": "false",
"x": 290,
"y": 60,
"wires": []
},
{
"id": "f5d126df.5b6928",
"type": "function",
"z": "b4106ec1.63dd58",
"name": "Save chat context",
"func": "msg.chatId = msg.payload.chatId;\nmsg.type = msg.payload.type;\nmsg.content = msg.payload.content;\nreturn msg;",
"outputs": 1,
"noerr": 0,
"x": 230,
"y": 160,
"wires": [
[
"c3d1a92d.227568"
]
]
},
{
"id": "276cfad7.cef62e",
"type": "function",
"z": "b4106ec1.63dd58",
"name": "Set Chat Context",
"func": "msg.payload = {\n chatId : msg.chatId,\n topic : msg.type,\n type : \"message\",\n content : msg.payload};\nreturn msg;\n",
"outputs": 1,
"noerr": 0,
"x": 730,
"y": 220,
"wires": [
[
"c6ec445d.0840d8"
]
]
},
{
"id": "c3d1a92d.227568",
"type": "switch",
"z": "b4106ec1.63dd58",
"name": "Check msg type",
"property": "type",
"propertyType": "msg",
"rules": [
{
"t": "eq",
"v": "message",
"vt": "str"
},
{
"t": "eq",
"v": "voice",
"vt": "str"
},
{
"t": "else"
}
],
"checkall": "true",
"repair": false,
"outputs": 3,
"x": 300,
"y": 240,
"wires": [
[
"e8452a44.f967c8"
],
[
"6aea6224.578d8c"
],
[]
]
},
{
"id": "e8452a44.f967c8",
"type": "function",
"z": "b4106ec1.63dd58",
"name": "Echo message",
"func": "msg.payload = {\n chatId : msg.chatId,\n topic : \"Text Echo\",\n type : msg.type,\n content : msg.content};\nreturn msg;",
"outputs": 1,
"noerr": 0,
"x": 540,
"y": 80,
"wires": [
[
"c6ec445d.0840d8"
]
]
},
{
"id": "6aea6224.578d8c",
"type": "change",
"z": "b4106ec1.63dd58",
"name": "Set voice URL",
"rules": [
{
"t": "set",
"p": "payload",
"pt": "msg",
"to": "payload.weblink",
"tot": "msg"
}
],
"action": "",
"property": "",
"from": "",
"to": "",
"reg": false,
"x": 440,
"y": 300,
"wires": [
[
"fc7b1590.557c"
]
]
},
{
"id": "493d1bac.216d3c",
"type": "change",
"z": "b4106ec1.63dd58",
"name": "Set transcription",
"rules": [
{
"t": "set",
"p": "payload",
"pt": "msg",
"to": "transcription",
"tot": "msg"
}
],
"action": "",
"property": "",
"from": "",
"to": "",
"reg": false,
"x": 680,
"y": 300,
"wires": [
[
"276cfad7.cef62e"
]
]
},
{
"id": "fc7b1590.557c",
"type": "watson-speech-to-text",
"z": "b4106ec1.63dd58",
"name": "S2T",
"alternatives": 1,
"speakerlabels": false,
"smartformatting": false,
"lang": "en-GB",
"langhidden": "en-GB",
"langcustom": "NoCustomisationSetting",
"langcustomhidden": "",
"custom-weight": "0.5",
"band": "BroadbandModel",
"bandhidden": "BroadbandModel",
"keywords": "",
"keywords-threshold": "0.5",
"word-confidence": false,
"password": "",
"apikey": "#########CHANGED VALUE TO POST###########",
"payload-response": false,
"streaming-mode": false,
"streaming-mute": true,
"auto-connect": false,
"discard-listening": false,
"disable-precheck": false,
"default-endpoint": true,
"service-endpoint": "https://stream.watsonplatform.net/speech-to-text/api",
"x": 530,
"y": 360,
"wires": [
[
"493d1bac.216d3c"
]
]
},
{
"id": "5f347711.7876d8",
"type": "telegram bot",
"z": "",
"botname": "FMWatsonBot",
"usernames": "",
"chatids": "",
"baseapiurl": "",
"updatemode": "polling",
"pollinterval": "300",
"bothost": "",
"localbotport": "8443",
"publicbotport": "8443",
"privatekey": "",
"certificate": "",
"verboselogging": false
}
]
Any hint?
Thanks in advance
Ferruccio
It boils down to how you are fetching the audio from Telegram. Check the answer to this related question - https://developer.ibm.com/answers/questions/424777/help-how-do-i-use-speech-to-text-with-my-telegram/
which shows how to build the url to send through to the Speech to text node.
Update: Flow perfectly works with telegram node v4.4.0, but fails with new version 5.1.5
So, it's not a problem regarding Speech to Text node.