How to add a link? I know how to add link to selection
const contentState = editorState.getCurrentContent();
const contentStateWithEntity = contentState.createEntity(
'LINK',
'MUTABLE',
{url: urlValue}
);
const entityKey = contentStateWithEntity.getLastCreatedEntityKey();
const newEditorState = EditorState.set(editorState, { currentContent: contentStateWithEntity });
this.setState({
editorState: RichUtils.toggleLink(
newEditorState,
newEditorState.getSelection(),
entityKey
)}
We get selection newEditorState.getSelection() and add link.
But how to add link without selection? Just add new a tag with text if text is not selected? It doesn't add anything if I doesn't select any text.
My really concise solution. With cool annotation
insertLink = (type, data, text) => {
const editorState = this.state.editorState;
const contentState = editorState.getCurrentContent();
const selection = editorState.getSelection();
const textWithSpace = text.concat(' ');
// create new content with text
const newContent = Modifier.insertText(
contentState,
selection,
textWithSpace,
);
// create new link entity
const newContentWithEntity = newContent.createEntity(
type,
'MUTABLE',
data,
false,
);
const entityKey = newContentWithEntity.getLastCreatedEntityKey();
// create new selection with the inserted text
const anchorOffset = selection.getAnchorOffset();
const newSelection = new SelectionState({
anchorKey: selection.getAnchorKey(),
anchorOffset,
focusKey: selection.getAnchorKey(),
focusOffset: anchorOffset + text.length,
});
// and aply link entity to the inserted text
const newContentWithLink = Modifier.applyEntity(
newContentWithEntity,
newSelection,
entityKey,
);
// create new state with link text
const withLinkText = EditorState.push(
editorState,
newContentWithLink,
'insert-characters',
);
// now lets add cursor right after the inserted link
const withProperCursor = EditorState.forceSelection(
withLinkText,
newContent.getSelectionAfter(),
);
// update the editor with all changes
this.setState({editorState: withProperCursor });
};
You can do any operations with the editor state without the component updating. So you can add a text that you need, after that programmatically set selection on this text and finally create a link and update your component.
Look at this working example - https://jsfiddle.net/levsha/2op5cyxm/
Here I add a link after a button click.
handleAddLink = () => {
const { editorState } = this.state;
const selectionState = editorState.getSelection();
const contentState = editorState.getCurrentContent();
const currentBlock = contentState.getBlockForKey(selectionState.getStartKey());
const currentBlockKey = currentBlock.getKey();
const blockMap = contentState.getBlockMap();
const blocksBefore = blockMap.toSeq().takeUntil((v) => (v === currentBlock));
const blocksAfter = blockMap.toSeq().skipUntil((v) => (v === currentBlock)).rest();
const newBlockKey = genKey();
// add new ContentBlock to editor state with appropriate text
const newBlock = new ContentBlock({
key: newBlockKey,
type: 'unstyled',
text: linkText,
characterList: new List(Repeat(CharacterMetadata.create(), linkText.length)),
});
const newBlockMap = blocksBefore.concat(
[[currentBlockKey, currentBlock], [newBlockKey, newBlock]],
blocksAfter
).toOrderedMap();
const selection = editorState.getSelection();
const newContent = contentState.merge({
blockMap: newBlockMap,
selectionBefore: selection,
selectionAfter: selection.merge({
anchorKey: newBlockKey,
anchorOffset: 0,
focusKey: newBlockKey,
focusOffset: 0,
isBackward: false,
}),
});
let newEditorState = EditorState.push(editorState, newContent, 'split-block');
// programmatically apply selection on this text
const newSelection = new SelectionState({
anchorKey: newBlockKey,
anchorOffset: 0,
focusKey: newBlockKey,
focusOffset: linkText.length
});
newEditorState = EditorState.forceSelection(newEditorState, newSelection);
// create link entity
const newContentState = newEditorState.getCurrentContent();
const contentStateWithEntity = newContentState.createEntity(
'LINK',
'IMMUTABLE',
{ url: linkUrl }
);
const entityKey = contentStateWithEntity.getLastCreatedEntityKey();
newEditorState = EditorState.set(newEditorState, { currentContent: contentStateWithEntity });
newEditorState = RichUtils.toggleLink(newEditorState, newEditorState.getSelection(), entityKey);
// reset selection
newSelection = new SelectionState({
anchorKey: newBlockKey,
anchorOffset: linkText.length,
focusKey: newBlockKey,
focusOffset: linkText.length
});
newEditorState = EditorState.forceSelection(newEditorState, newSelection);
// update our component
this._handleChange(newEditorState);
}
Related
I'm trying to insert my custom block to the editorState of draft-js's editor. I can't seem to find any detailed information on how to accomplish this.
Block Renderer:
const blockRendererFn = (contentBlock) => {
const type = contentBlock.getType();
if (type === 'CustomTestChipBlock') {
return {
component: CustomTestChipBlock,
editable: false,
props: {
foo: 'bar',
},
};
}
}
Block Render Map:
import { DefaultDraftBlockRenderMap } from "draft-js";
import { Map } from 'immutable';
const blockRenderMap = Map({
CustomTestChipBlock: {
element: 'div',
}
}).merge(DefaultDraftBlockRenderMap);
My custom block (material ui chip):
import { Chip } from "#mui/material";
const CustomTestChipBlock = (props) => {
const { block, contentState } = props;
const { foo } = props.blockProps;
const data = contentState.getEntity(block.getEntityAt(0)).getData();
console.log("foo: "+foo)
console.log("data: "+data)
return (
<Chip label="test" size="small"/>
)
}
Now my problem is when I try to insert my custom block. I assume my method of insertion must be wrong. I tried multiple insertion methods but due to lack of any detailed information on the subject, all of them ended up not even running the console.log inside my custom component.
Insertion:
const addChip = () => {
setEditorState(insertBlock("CustomTestChipBlock"));
}
const insertBlock = (type) => {
// This is where I can't find any detailed info at all
const newBlock = new ContentBlock({
key: genKey(),
type: type,
text: "",
characterList: List(),
});
const contentState = editorState.getCurrentContent();
const newBlockMap = contentState.getBlockMap().set(newBlock.key, newBlock);
const newEditorState = ContentState.createFromBlockArray(
newBlockMap.toArray()
)
.set("selectionBefore", contentState.getSelectionBefore())
.set("selectionAfter", contentState.getSelectionAfter());
return EditorState.push(editorState, newEditorState, "add-chip");
};
I have this code in my messageCreate event:
// MODULES
const Discord = require('discord.js');
const mongoose = require('mongoose');
const Levels = require('discord.js-leveling');
// FILES
const Guild = require('../../models/guild');
const config = require('../../files/config.json');
const swearwords = require("../../files/data.json");
const colors = require('../../files/colors.json');
// ERROR MESSAGE
const errorMain = new Discord.MessageEmbed()
.setDescription("There was an error!")
.setColor(colors.COLOR)
const addedDatabase = new Discord.MessageEmbed()
.setDescription("This server is now added to our database.")
.setColor(colors.COLOR)
module.exports = async (Discord, client, message) => {
if (!message.guild) return;
if (message.author.bot) return;
const settings = await Guild.findOne({
guildID: message.guild.id
}, (err, guild) => {
if (err) message.channel.send(errorMain);
if (!guild) {
const newGuild = new Guild({
_id: mongoose.Types.ObjectId(),
guildID: message.guild.id,
prefix: config.PREFIX,
logChannelID: String,
enableLog: false,
enableSwearFilter: true,
enableMusic: true,
enableLevel: true,
});
newGuild.save()
.catch(err => message.channel.send(errorMain));
return message.channel.send({embeds: [addedDatabase]}).then(m => m.delete({ timeout: 10000 }))
}
});
// VARIABLES
const IDGuild = message.guild.id;
const user = message.author;
const prefix = settings.prefix;
const swearFilterOn = settings.enableSwearFilter;
// LEVEL SYSTEM
if (settings.enableLevel === "true") {
const requiredXp = Levels.xpFor(parseInt(user.level) + 1)
const randomAmountOfXp = Math.floor(Math.random() * 29) + 1;
const hasLeveledUp = await Levels.appendXp(message.author.id, message.guild.id, randomAmountOfXp);
if (hasLeveledUp) {
const user = await Levels.fetch(message.author.id, message.guild.id);
const levelEmbed = new Discord.MessageEmbed()
.setTitle('New Level!')
.setColor(colors.COLOR)
.setDescription(`**GG** ${message.author}, you just leveled up to level **${user.level}**!\nContiune to chat to level up again.`)
const sendEmbed = await message.channel.send({embeds: [levelEmbed]});
}
}
// EXECUTE COMMAND AND SWEARFILTER
if (swearFilterOn === "true") {
var msg = message.content.toLowerCase();
for (let i = 0; i < swearwords["swearwords"].length; i++) {
if (msg.includes(swearwords["swearwords"][i])) {
message.delete();
return message.channel.send("Please do not swear.").then(msg => msg.delete({ timeout: 3000 }));
}
}
if (!message.content.startsWith(prefix) || message.author.bot) return;
const args = message.content.slice(prefix.length).split(/ +/);
const cmd = args.shift().toLowerCase();
const command = client.commands.get(cmd) ||
client.commands.find(a => a.aliases && a.aliases.includes(cmd));;
if (command) command.execute(client, message, args, Discord)
} else {
if (!message.content.startsWith(prefix) || message.author.bot) return;
const args = message.content.slice(prefix.length).split(/ +/);
const cmd = args.shift().toLowerCase();
const command = client.commands.get(cmd) ||
client.commands.find(a => a.aliases && a.aliases.includes(cmd));;
if (command) command.execute(client, message, args, Discord)
}
}
And when i send a message right after the bot joines the discord, it gives the error that it cannot read properties of null (reading 'prefix').
The bot crashes, and when it's restarted it works because it has been added to the Database. So how can i fix that when it sends the first message it can still read 'prefix'. its probably a database issue.
I was told that settings.prefix probaly wasn't assinged a value, is there a way to fix this?
I'm using mongodb for my database.
You really should assign the prefix right after the bot joins new server with guildCreate event. It may cause some issues if your database is down etc. When you wait till the message event
I am new to react native. I have created a form from where I am sending some data to server. Now I want that to disabled submit button after user click on submit . once user submit data then after He unable to send data. means I want to avoid duplicate entry. please help. thanks. if possible also tell how to do it with functional component too.
here is my code
export default function Add(props) {
const { navigation } = props
const offset = (Platform.OS === 'android') ? -200 : 0;
const [AmazonError, setAmazonError] = useState([]);
const [Amazon, setAmazon] = useState('');
const [AmazonCNError, setAmazonCNError] = useState([]);
const [AmazonCN, setAmazonCN] = useState('');
const [AEPSError, setAEPSError] = useState([]);
const [AEPS, setAEPS] = useState('');
const [DMTError, setDMTError] = useState([]);
const [DMT, setDMT] = useState('');
const [BBPSError, setBBPSError] = useState([]);
const [BBPS, setBBPS] = useState('');
const [leadTagNumber, setLeadTagNumber] = useState([]);
const validateInputs = () => {
if (!Amazon.trim()) {
setAmazonError('Please Fill The Input')
return;
}
if (!AmazonCN.trim()) {
setAmazonCNError('Please Fill The Input')
return;
}
if (!AEPS.trim()) {
setAEPSError('Please Fill The Input')
return;
}
if (!DMT.trim()) {
setDMTError('Please Fill The Input')
return;
}
if (!BBPS.trim()) {
setBBPSError('Please Fill The Input')
return;
}
else
{
//+++++++++++++++++++++++++++++++++=submitting form data to api start+++++++++++++++++++++++++++++++++++
{
const leadTagNumber = props.route.params.leadTagNumber
AsyncStorage.multiGet(["application_id", "created_by",'leadTagNumber']).then(response => {
// console.log(response[0][0]) // Key1
console.log(response[0][1]) // Value1
// console.log(response[1][0]) // Key2
console.log(response[1][1]) // Value2
console.log(leadTagNumber)
fetch('https://xyxtech/Android_API_CI/uploaddata/tbservice_details', {
method: 'POST',
headers: {'Accept': 'application/json, text/plain, */*', "Content-Type": "application/json" },
// We convert the React state to JSON and send it as the POST body
body: JSON.stringify([{ data}])
})
.then((returnValue) => returnValue.json())
.then(function(response) {
console.log(response)
Alert.alert("File uploaded");
return response.json();
});
});
// event.preventDefault();
}
//+++++++++++++++++++++++++++++++++submitting form data to api end++++++++++++++++++++++++++++++++++++++
Alert.alert("success")
return;
//}
}
};
const handleAmazon = (text) => {
setAmazonError('')
setAmazon(text)
}
const handleAmazonCN= (text) => {
setAmazonCNError('')
setAmazonCN(text)
}
const handleAEPS= (text) => {
setAEPSError('')
setAEPS(text)
}
const handleDMT = (text) => {
setDMTError('')
setDMT(text)
}
const handleBBPS = (text) => {
setBBPSError('')
setBBPS(text)
}
return (
<View style={{flex: 1}}>
<ScrollView style={{flex: 1,}} showsVerticalScrollIndicator={false}>
<TextInput
maxLength={30}
placeholder="AEPS (Adhar enabled payment system) *"
style={styles.inputStyle}
onChangeText={(text)=>handleAEPS(text)}
defaultValue={AEPS}
value = {AEPS} />
<Text>{AEPSError}</Text>
</ScrollView>
<Button
style={styles.inputStyleB}
title="Submit"
color="#FF8C00"
onPress={() => validateInputs()}
/>
</View>
)
}
Set new state property to enable/disable button
const [disableButton, setDisableButton] = useState(false);
Now in your button component, add disabled property with disableButton state.
<Button
style={styles.inputStyleB}
title="Submit"
color="#FF8C00"
onPress={() => validateInputs()}
disabled={disableButton}
/>
Disable you button before fetching data
setDisableButton(true) //Add this
const leadTagNumber = props.route.params.leadTagNumber
Incase of fetch error or after fetching is complete, enable button again
setDisabledButton(false)
I have a following return from my component
<div className="content page-with-map" >
<div className='route-editor'>
<Loader loading={routeSectionsLoadingList}/>
{this.renderRouteSectionsList()}
<div className='route-map-block'>
<MapComponent className='route-map'>
<Pane name='RouteSections' style={{ zIndex: 300 }}>
<RouteSectionsLayer
isAdd={isAdd}
isEdit={isEdit}
linesData={routeSectionsFeaturesList}
selectedLine={selectedSection}
setSelectedLine={this.handleSelectSection}
hoveredLine={hoveredSection}
onMouseOverLine={this.onMouseOver}
onMouseOutLine={this.onMouseOut}
/>
</Pane>
</MapComponent>
</div>
</div>
</div>
);
and here is my MapComponent, where i take children and add some custom props. Also rendering map on condition of higher div added to the DOM:
const cityBounds = CITY_BOUNDS;
// State
const [bounds, setBounds] = useState(cityBounds);
const [renderMap, setRenderMap] = useState(false);
const [zoom, setZoom] = useState();
const leafletContainerRef = useRef(null);
useEffect(() => {
if (leafletContainerRef.current) {
setRenderMap(true);
}
}, [leafletContainerRef.current]);
const onViewportChanged = (viewport) => {
const { zoom } = viewport;
setZoom(zoom);
};
const onBoundsChanged = (bounds) => {
setBounds(bounds);
};
const {
className,
children,
} = props;
let customProps = {};
return (
<div className={classNames('leaflet-container', className)} ref={leafletContainerRef}>
{renderMap ?
<MapContainer
bounds={bounds}
doubleClickZoom={false}
crs={L.CRS.EPSG3395}
onViewportChanged={onViewportChanged}
>
<TileLayer
url="https://vec{s}.maps.yandex.net/tiles?l=map&v=20.07.01-0&x={x}&y={y}&z={z}&scale=1&lang=ru_RU"
subdomains={['01', '02', '03', '04']}
attribution='<a http="yandex.ru" target="_blank">Яндекс</a>'
/>
{React.Children.map(children, child => {
customProps = { ...customProps, onBoundsChanged: onBoundsChanged, bounds: bounds };
return React.cloneElement(child, customProps);
})}
</MapContainer>
: null}
</div>
);
}
And also RouteSectionsLayer component:
export default function RouteSectionsLayer(props) {
const { isEdit = false, selectedLine } = props;
const getLines = () => {
const { onMouseOverLine = () => {}, onMouseOutLine = () => {}, linesData = [] } = props;
return linesData && linesData.length ?
linesData.map((lineFeature, i) => {
const lineIndex = i;
return <Polyline
key={hash(lineIndex)}
pane={'RouteSections'}
positions={lineFeature.geometry
&& lineFeature.geometry.coordinates
&& lineFeature.geometry.coordinates.map(line => line.map(vertex => vertex.map(coordinate => +coordinate)))}
attribution={`${i}`}
lineIndex={lineIndex}
pathOptions={{
color: 'black',
weight: 5,
}}
/>;
})
: null;
};
return (
getLines()
);
}
While rendering i get "Uncaught TypeError: Cannot read property 'appendChild' of undefined". What am i doing wrong?
UPDATE: I tried to rewrote RouteSectionsLayer following core architecture example from docs, now it looks like this:
export default function RouteSectionsLayer(props) {
const leafletContext = useLeafletContext();
const getLinesData = () => {
const { input, linesData = [] } = props;
if (input && input.value) {
return input.value;
}
return linesData;
};
useEffect(() => {
const container = leafletContext.layerContainer || leafletContext.map;
const linesData = getLinesData();
const polyLinesInstances = linesData && linesData.length ?
linesData.map((lineFeature, lineIndex) => {
const latlngs = lineFeature.geometry && coordsToNumbers(lineFeature.geometry.coordinates);
const layerOptions = {
attribution: `${lineIndex}`,
pane: 'RouteSections'
};
const pathOptions = normalRouteSectionStylePathOptions;
const polyLineOptions = {
lineIndex: { lineIndex },
...layerOptions,
...pathOptions
};
return new L.Polyline(latlngs, polyLineOptions)
})
: [];
const layerGroupInstance = new L.LayerGroup(polyLinesInstances);
container.addLayer(layerGroupInstance);
return () => {
container.removeLayer(layerGroupInstance);
};
});
const coordsToNumbers = (lineCoordinates) => {
return lineCoordinates && lineCoordinates.length ?
lineCoordinates.map(line => line.map(vertex => vertex.map(coordinate => +coordinate)))
: null;
};
And the error is still here
well, i found my mistake. In re-wrote RouteSectionsLayer i deleted pane in the options of the polyline:
const layerOptions = {
attribution: `${lineIndex}`,
pane: 'RouteSections' // <-- i deleted this.
};
It seams that the pane 'RouteSections' i created as a child of MapComponent was not found.
As you can see, I am connecting to the database, reading multiple JSON files from a directory and import them into the MongoDB server with help of mongoose.
After this job is done, I would like to close the connection and print out "job is done"
How do I do that?
var mongoose = require('mongoose'),
_ = require('lodash'),
fs = require('fs'),
path = require('path');
mongoose.Promise = require('bluebird'),
mongoose.connect('mongodb://localhost/eclass');
var db = mongoose.connection;
db.on('error', console.error.bind(console, 'connection error:'));
db.once('open', function() {
// we're connected!
// create db schema
var EclassSchema = new mongoose.Schema({
xsi: {
xsitype: 'string',
id: 'string'
},
date_of_original_definition: 'string',
date_of_current_version: 'string',
date_of_current_revision: 'string',
revision: 'string',
status: 'string',
source_language: {
country_code: 'string',
language_code: 'string'
},
preferred_name: 'string',
definition: 'string',
its_superclass: 'string',
hierarchical_position: 'string',
//keywords: 'string'
});
// Create model
var Eclass = mongoose.model('Eclass', EclassSchema);
const pjsons = path.join(__dirname, '/../', 'file-operations', 'json-files');
console.log(pjsons);
function readFiles(pjsons, onError) {
fs.readdir(pjsons, function(err, filenames) {
if(err) {
onError(err);
return;
}
filenames.forEach(function(filename) {
fs.readFile(pjsons + '/' + filename, 'utf-8', function(err, data) {
if(err) {
onError(err);
return;
}
data = JSON.parse(data);
// Digging down into the json code
const ontomlOntoml = data['dic:eclass_dictionary']['ontoml:ontoml'];
const onto = _.first(ontomlOntoml);
const dictionary = onto['dictionary'];
const contClasses = _.first(dictionary);
const containedClasses = contClasses['contained_classes'];
const ontClass = _.first(containedClasses);
const ontomlClass = _.find(ontClass);
//Arrays
const xsiArray = _.map(ontomlClass, '$');
const date_of_original_definitionArray = _.map(ontomlClass, 'date_of_original_definition');
const date_of_current_versionArray = _.map(ontomlClass, 'date_of_current_version');
const date_of_current_revisionArray = _.map(ontomlClass, 'date_of_current_revision');
const revisionArray = _.map(ontomlClass, 'revision');
const statusArray = _.map(ontomlClass, 'status');
const sourceLanguageArray = _.map(ontomlClass, 'source_language');
const preferredNameArray = _.map(ontomlClass, 'preferred_name');
const definitionArray = _.map(ontomlClass, 'definition');
const itsSuperclassArray = _.map(ontomlClass, 'its_superclass');
const hierarchical_positionArray = _.map(ontomlClass, 'hierarchical_position');
//const keywordsArray = _.map(ontomlClass, 'keywords');
// Looping and storing the data into mongodb
//for (var i = 0; i < hierarchical_positionArray.length; i++) {
for (var i = 0; i < 2; i++) {
//console.log(hierarchical_positionArray[i]);
var newEclass = new Eclass();
newEclass.xsi.xsitype = xsiArray[i]['xsi:type'];
newEclass.xsi.id = xsiArray[i]['id'];
newEclass.date_of_original_definition = date_of_original_definitionArray[i];
newEclass.date_of_current_version = date_of_current_versionArray[i];
newEclass.date_of_current_revision = date_of_current_revisionArray[i];
newEclass.revision = revisionArray[i];
newEclass.status = statusArray[i];
newEclass.source_language.country_code = sourceLanguageArray[i][0].$.country_code;
newEclass.source_language.language_code = sourceLanguageArray[i][0].$.language_code;
newEclass.preferred_name = preferredNameArray[i][0].label[0]._;
newEclass.definition = definitionArray[i][0].text[0]._;
newEclass.its_superclass = itsSuperclassArray[i][0].$.class_ref;
newEclass.hierarchical_position = hierarchical_positionArray[i];
//newEclass.keywords = keywordsArray[i][0].label[0]._;
newEclass.save(function (err) {});
}
});
});
});
}
readFiles(pjsons);
});
mongoose.disconnect() closes all opened connections. for more
http://mongoosejs.com/docs/api.html#index_Mongoose-disconnect
I solved it like this:
newEclass.save()
.then(function() {
mongoose.disconnect();
})
.catch(function(err) {
console.log('There was an error', err);
});
...
const mongoose = require('mongoose'),
parse = require('csv-parse'),
path = require('path'),
fs = require('fs');
mongoose.Promise = require('bluebird');
mongoose.connect('mongodb://localhost/eclassCSV');
const db = mongoose.connection;
db.on('error', console.error.bind(console, 'connection error:'));
db.once('open', function() {
// we're connected!
// create db schema
const EclassSchema = new mongoose.Schema({
codedName: { type: String, min: 10, max: 10 },
preferredName: { type: String, max: 80 },
definition: { type: String, max: 1023 },
level: { type: String, min: 1, max: 1 },
mkSubclass: { type: String, min: 1, max: 1 },
mkKeyword: { type: String, min: 1, max: 1 }
});
// Create MongoDB model with mongoose
const Eclass = mongoose.model('Eclass', EclassSchema);
const p = path.join(__dirname, '/../', 'file-operations', 'csv-files');
//console.log(p);
const parser = parse({delimiter: ';'}, function(err, data){
//console.log(data);
//const supplier = data[0][0];
const codedName = data.map((item,i) => data[i][6]);
const preferredName = data.map((item,i) => data[i][7]);
const definition = data.map((item,i) => data[i][8]);
const level = data.map((item,i) => data[i][13]);
const mkSubclass = data.map((item,i) => data[i][14]);
const mkKeyword = data.map((item,i) => data[i][15]);
// Looping and storing the data into mongodb
//console.log(ontomlClass.length);
for (let i = 0; i < data.length; i++) {
//console.log(hierarchical_positionArray[i]);
const newEclass = new Eclass();
newEclass.codedName = codedName[i];
newEclass.preferredName = preferredName[i];
newEclass.definition = definition[i];
newEclass.level = level[i];
newEclass.mkSubclass = mkSubclass[i];
newEclass.mkKeyword = mkKeyword[i];
newEclass.save()
.then(function() {
mongoose.disconnect();
})
.catch(function(err) {
console.log('There was an error', err);
});
}
});
fs.createReadStream(p + '/One-eClass-10_0_CC_en.csv').pipe(parser);
});