Split sentence by space mixed up my index - javascript

I'm facing some problem while trying to send text to some spelling API.
The API return the corrections based on the words index, for example:
sentence:
"hello hoow are youu"
So the API index the words by numbers like that and return the correction based on that index:
0 1 2 3
hello hoow are youu
API Response that tell me which words to correct:
1: how
3: you
On the code I using split command to break the sentence into words array so I will be able to replace the misspelled words by their index.
string.split(" ");
My problem is that the API trim multiple spaces between words into one space, and by doing that the API words index not match my index. (I would like to preserve the spaces on the final output)
Example of the problem, sentence with 4 spaces between words:
Hello howw are youu?
0 1 2 3 4 5 6 7
hello hoow are youu
I thought about looping the words array and determine if the element is word or space and then create something new array like that:
indexed_words[0] = hello
indexed_words[0_1] = space
indexed_words[0_2] = space
indexed_words[0_3] = space
indexed_words[0_4] = space
indexed_words[0_5] = space
indexed_words[0_6] = space
indexed_words[0_7] = space
indexed_words[1] = how
indexed_words[2] = are
indexed_words[3] = you?
That way I could replace the misspelled words easily and than rebuild the sentence back with join command but the problem but the problem that I cannot use non-numeric indexes (its mixed up the order of the array)
Any idea how I can keep the formatting (spaces) but still correct the words?
Thanks

in that case you have very simple solution:L
$(document).ready(function(){
var OriginalSentence="howw are you?"
var ModifiedSentence="";
var splitstring=OriginalSentence.split(' ')
$.each(splitstring,function(i,v){
if(v!="")
{
//pass this word to your api and appedn it to sentance
ModifiedSentence+=APIRETURNVALUE//api return corrected value;
}
else{
ModifiedSentence+=v;
}
});
alert(ModifiedSentence);
});

Please review this one:
For string manipulation like this, I would highly recommend you to use Regex
Use online regex editor for faster try and error like here https://regex101.com/.
here I use /\w+/g to match every words if you want to ignore 1 or two words we can use /\w{2,}/g or something like that.
var str = "Hello howw are youu?";
var re = /\w+/g
var words = str.match(re);
console.log("Returning valus")
words.forEach(function(word, index) {
console.log(index + " -> " + word);
})
Correction
Just realize that you need to keep spacing as it is, please try this one:
I used your approach to change all to space. create array for its modified version then send to your API (I dunno that part). Then get returned data from API, reconvert it back to its original formating string.
var ori = `asdkhaskd asdkjaskdjaksjd askdjaksdjalsd a ksjdhaksjdhasd asdjkhaskdas`;
function replaceMeArr(str, match, replace) {
var s = str,
reg = match || /\s/g,
rep = replace || ` space `;
return s.replace(reg, rep).split(/\s/g);
}
function replaceMeStr(arr, match, replace) {
var a = arr.join(" "),
reg = match || /\sspace\s/g,
rep = replace || " ";
return a.replace(reg, rep);
}
console.log(`ori1: ${ori}`);
//can use it like this
var modified = replaceMeArr(ori);
console.log(`modi: ${modified.join(' ')}`);
//put it back
var original = replaceMeStr(modified);
console.log(`ori2: ${original}`);

Updated
var str = "Hello howw are youu?";
var words = str.split(" ");
// Getting an array without spaces/empty values
// send it to your API call
var requestArray = words.filter(function(word){
if (word) {
return word;
}
});
console.log("\nAPI Response that tell me which words to correct:");
console.log("6: how\n8: you");
var response = {
"1": "how",
"3": "you"
}
//As you have corrected words index, Replace those words in your "requestArray"
for (var key in response) {
requestArray[key] = response[key];
}
//now we have array of non-empty & correct spelled words. we need to put back empty (space's) value back in between this array
var count = 0;
words.forEach(function(word, index){
if (word) {
words[index] = requestArray[count];
count++;
}
})
console.log(words);
Correct me, if i was wrong.
Hope this helps :)

Try this JSFiddle
, Happy coding :)
//
// ReplaceMisspelledWords
//
// Created by Hilal Baig on 21/11/16.
// Copyright © 2016 Baigapps. All rights reserved.
//
var preservedArray = new Array();
var splitArray = new Array();
/*Word Object to preserve my misspeled words indexes*/
function preservedObject(pIndex, nIndex, title) {
this.originalIndex = pIndex;
this.apiIndex = nIndex;
this.title = title;
}
/*Preserving misspeled words indexes in preservedArray*/
function savePreserveIndexes(str) {
splitArray = str.split(" ");
//console.log(splitArray);
var x = 0;
for (var i = 0; i < splitArray.length; i++) {
if (splitArray[i].length > 0) {
var word = new preservedObject(i, x, splitArray[i]);
preservedArray.push(word);
x++;
}
}
};
function replaceMisspelled(resp) {
for (var key in resp) {
for (var i = 0; i < preservedArray.length; i++) {
wObj = preservedArray[i];
if (wObj.apiIndex == key) {
wObj.title = resp[key];
splitArray[wObj.originalIndex] = resp[key];
}
}
}
//console.log(preservedArray);
return correctedSentence = splitArray.join(" ");
}
/*Your input string to be corrected*/
str = "Hello howw are youu";
console.log(str);
savePreserveIndexes(str);
/*API Response in json of corrected words*/
var apiResponse = '{"1":"how","3":"you" }';
resp = JSON.parse(apiResponse);
//console.log(resp);
/*Replace misspelled words by corrected*/
console.log(replaceMisspelled(resp)); //Your solution

Related

Changing individual characters in a string does not work in a loop [duplicate]

This question already has answers here:
The .replace() method does change the string in place [duplicate]
(3 answers)
Closed 4 years ago.
So, I'm working on some exercise questions. My code seems to be working fine up until I decide to loop through the string to replace any instance of a period with nothing. For some reason, the loop doesn't work. I imagine it has something to do with not calling it somehow, but I'm not sure how to call the loop. I thought that loops automatically overwrote what they are looping through. Here is the exercise and my incomplete solution:
Write a JavaScript function to parameterize a string.
function string_parameterize(string) {
var lowercase_string = string.toLowerCase();
var split_string = lowercase_string.split(" ");
var joined_string = split_string.join("-");
for (i = 0; i < joined_string.length; i++) {
if (joined_string[i] === ".") {
joined_string[i] === "";
}
}
return joined_string;
}
//Test Data :
console.log(string_parameterize("Robin Singh from USA."));
The answer should be robin-singh-from-usa without the period, but it keeps coming out as robin-singh-from-usa. with the period.
The other answers are not taking into account that strings in JavaScript are immutable. You can not change individual characters in a string. You build a new string.
In JavaScript, strings are immutable. Trying to change the characters in a string does not work:
function string_parameterize(string) {
var lowercase_string = string.toLowerCase();
var split_string = lowercase_string.split(" ");
var joined_string = split_string.join("-");
for (i = 0; i < joined_string.length; i++) {
if (joined_string[i] === ".") {
joined_string[i] = "";
}
}
return joined_string;
}
//Test Data :
console.log(string_parameterize("Robin Singh from USA.")); //This will not work:
You can build a new string using your for loop to individually add each character that is not a . to the newString:
function string_parameterize(string) {
var lowercase_string = string.toLowerCase();
var split_string = lowercase_string.split(" ");
var joined_string = split_string.join("-");
var newString = '';
for (i = 0; i < joined_string.length; i++) {
if (joined_string[i] !== ".") {
newString += joined_string[i];
} //We are replacing '.' with nothing, '', so no need for an else
}
return newString;
}
//Test Data :
console.log(string_parameterize("Robin Singh from USA."));
Regular Expressions
This would, however, normally be done with Regular Expressions, specifically the .replace() method:
function string_parameterize(string) {
var lowercase_string = string.toLowerCase();
var newString = lowercase_string.replace(/ /g,'-'); //Replace all spaces with '-'.
var newString = newString.replace(/\./g,''); //Replace all '.' with nothing. The '.'
// has to be quoted with \. as it
// has special meaning in a RegExp.
return newString;
}
//Test Data :
console.log(string_parameterize("Robin Singh from USA."));
Which can be done all in one statement:
function string_parameterize(string) {
return string.toLowerCase().replace(/ /g,'-').replace(/\./g,'');
}
//Test Data :
console.log(string_parameterize("Robin Singh from USA."));
You can put in a [...]+ every character you don't want have in the output.
var res = string.toLowerCase().replace(/[%\(\)\.\s]+/g, "-").replace(/-$/, "");
// ^ ^ ^ ^
// Here the characters you don't want to have in the output
+ means matched one ore more times. Replace the matched characters with -.
Then remove last - with -$.
In total
function string_parameterize(string) {
var res = string.toLowerCase().replace(/[%\(\)\.\s]+/g, "-").replace(/-$/, "");
return res;
}
console.log(string_parameterize("Это тест")); // A russian sentence
console.log(string_parameterize("Robin Singh%%() from USA. "));
console.log(string_parameterize("Robin ...Singh from USA....."));
console.log(string_parameterize("Robin Singh from USA "));
console.log(string_parameterize("Robin Singh from USA"));
Info about regular expression.
function string_parameterize(string) {
var lowercase_string = string.toLowerCase();
var split_string = lowercase_string.split(" ");
var joined_string = split_string.join("-");
joined_string = joined_string.replace(".", "");
return joined_string;
}
//Test Data :
console.log(string_parameterize("Robin Singh from USA."));
This is working in IE.
function string_parameterize(str){
return str.toLowerCase().replace(".", "").split(" ").join("-");
}
console.log(string_parameterize("Robin Singh from USA."));
//will result in: robin-singh-from-usa
Your code is not working because in if condition you are checking for joined_string[i]==="." to be equal to '.' and actually it is equal to 'USA.'. That is why this if condition never met with and return the '.' in the final result:
if (joined_string[i]===".") {
joined_string[i]==="";
}
You're checking the value of joined_string[i], rather than assigning it.
joined_string[i] = "";
not
joined_string[i] === "";
Change:
if (joined_string[i]===".") {
joined_string[i]==="";
}
to
if (joined_string[i]===".") {
joined_string[i]="";
}

Please explain to me prototypes in javascript using the code below

I am trying to use the prototype method of writing functions that can be implemented by strings to capitalise every first letter of every word. I would like to call this function like,
var str = "Example of a string";
str.toJadenCase();
This is the function I am trying to write:
String.prototype.toJadenCase = function () {
//split the statement into each word
if (String.prototype.length !== 0)
{
var eachWord = String.prototype.split(" ");
var n = eachWord.length;
if(n !== 0)
{
//loop through the array of words
for(var i = 0; i < eachWord.length; i++){
//for each loop, split the word into individual characters
var charArray = eachWord[i].split("");
//capitalise the first element of character array
charArray[0] = charArray[0].toUpperCase();
//join all elements in character array to string
eachWord[i] = charArray.join("");
}
//join all the words to form the statement
String.prototype = eachWord.join(" ");
return String.prototype;
}
}
};
I had written it this way before:
var capitaliseInitial = function(sampleText){
var textString = sampleText;
//split the statement into each word
var eachWord = textString.split(" ");
//loop through the array of words
for(var i = 0; i < eachWord.length; i++){
//for each loop, split the word into individual characters
var charArray = eachWord[i].split("");
//capitalise the first element of character array
charArray[0] = charArray[0].toUpperCase();
//join all elements in character array to string
eachWord[i] = charArray.join("");
}
//join all the words to form the statement
textString = eachWord.join(" ");
return textString;
}
I would like to call this function like,
var str = "Example of a string";
str.toJadenCase();
You can't, strings are immutable. You would have to call it like this:
str = str.toJadenCase();
In your function, you're using String.prototype incorrectly. String.prototype is the object containing the various String-specific methods. It's assigned as the underlying prototype of all strings.
Where you're using String.prototype, you should be using this, and instead of trying to assign to it (this = ... is invalid), return the result.
The simple way to do what you're doing is to:
Split the string into an array of words, as you have
Loop through that array either building up a new string with the capitalized words via +=, or building a new array with the capitalized words and then doing Array#join at the end to put it back together.
Return the string you built
Something like this:
String.prototype.toJadenCase = function() {
var result = this;
//split the statement into each word
if (this.length !== 0) {
result = this.split(" ").map(function(word) {
return word.substring(0, 1).toUpperCase() + word.substring(1);
}).join(" ");
}
return result;
};
snippet.log("this is a test".toJadenCase());
snippet.log("oneword".toJadenCase());
snippet.log("blank: " + ("".toJadenCase()));
<!-- Script provides the `snippet` object, see http://meta.stackexchange.com/a/242144/134069 -->
<script src="http://tjcrowder.github.io/simple-snippets-console/snippet.js"></script>
Note I've done away with the check if the array of words' length isn't 0: It can't be 0 if you've pre-checked the length as you have.
use RegExp and php like naming
str.ucwords()
String.prototype.ucwords = function() {
return this.replace(/\b\S/g,function(c){
return c.toUpperCase()
}
}
Here's how I did mine.
Split the string into an array of words, as you have
Loop through that array either building up a new string with the capitalized words via +=, or building a new array with the capitalized words and then doing Array#join at the end to put it back together.
Return the string you built
String.prototype.toJadenCase = function () { return this.split(" ").map(function(word){ return word.charAt(0).toUpperCase() + word.slice(1); }).join(" "); }
This look like one of the Code Wars Katas - this was my solution -
String.prototype.toJadenCase = function () {
// assign 'this' keyword to a variable and split String into an array
var result = this.split(" ");
/* loop through the array changing first character of each item to
uppercase & adding it to the remaining letters in each item */
for(i = 0; i < result.length; i++) {
result[i] = result[i].charAt(0).toUpperCase() + result[i].substring(1);
}
//finally return items joined back together in a string
return result.join(' ');
};
another way to do this would be like:
String.prototype.toJadenCase = function() {
return this
.split(" ")
.map(i => i.replace(i[0], i[0].toUpperCase()))
.join(" ");
};

Bold part of String

What is the best way to bold a part of string in Javascript?
I have an array of objects. Each object has a name. There is also an input parameter.
If, for example, you write "sa" in input, it automatically searches in array looking for objects with names that contain "sa" string.
When I print all the names, I want to bold the part of the name that coincide with the input text.
For example, if I search for "Ma":
Maria
Amaria
etc...
I need a solution that doesn't use jQuery. Help is appreciated.
PD: The final strings are in the tag. I create a list using angular ng-repeat.
This is the code:
$scope.users = data;
for (var i = data.length - 1; i >= 0; i--) {
data[i].name=data[i].name.replace($scope.modelCiudad,"<b>"+$scope.modelCiudad+"</b>");
};
ModelCiudad is the input text content var. And data is the array of objects.
In this code if for example ModelCiudad is "ma" the result of each is:
<b>Ma</b>ria
not Maria
You can use Javascript's str.replace() method, where str is equal to all of the text you want to search through.
var str = "Hello";
var substr = "el";
str.replace(substr, '<b>' + substr + '</b>');
The above will only replace the first instance of substr. If you want to handle replacing multiple substrings within a string, you have to use a regular expression with the g modifier.
function boldString(str, substr) {
var strRegExp = new RegExp(substr, 'g');
return str.replace(strRegExp, '<b>'+substr+'</b>');
}
In practice calling boldString would looks something like:
boldString("Hello, can you help me?", "el");
// Returns: H<b>el</b>lo can you h<b>el</b>p me?
Which when rendered by the browser will look something like: Hello can you help me?
Here is a JSFiddle with an example: https://jsfiddle.net/1rennp8r/3/
A concise ES6 solution could look something like this:
const boldString = (str, substr) => str.replace(RegExp(substr, 'g'), `<b>${substr}</b>`);
Where str is the string you want to modify, and substr is the substring to bold.
ES12 introduces a new string method str.replaceAll() which obviates the need for regex if replacing all occurrences at once. It's usage in this case would look something like this:
const boldString = (str, substr) => str.replaceAll(substr, `<b>${substr}</b>`);
I should mention that in order for these latter approaches to work, your environment must support ES6/ES12 (or use a tool like Babel to transpile).
Another important note is that all of these approaches are case sensitive.
Here's a pure JS solution that preserves the original case (ignoring the case of the query thus):
const boldQuery = (str, query) => {
const n = str.toUpperCase();
const q = query.toUpperCase();
const x = n.indexOf(q);
if (!q || x === -1) {
return str; // bail early
}
const l = q.length;
return str.substr(0, x) + '<b>' + str.substr(x, l) + '</b>' + str.substr(x + l);
}
Test:
boldQuery('Maria', 'mar'); // "<b>Mar</b>ia"
boldQuery('Almaria', 'Mar'); // "Al<b>mar</b>ia"
I ran into a similar problem today - except I wanted to match whole words and not substrings. so if const text = 'The quick brown foxes jumped' and const word = 'foxes' than I want the result to be 'The quick brown <strong>foxes</strong> jumped'; however if const word = 'fox', than I expect no change.
I ended up doing something similar to the following:
const pattern = `(\\s|\\b)(${word})(\\s|\\b)`;
const regexp = new RegExp(pattern, 'ig'); // ignore case (optional) and match all
const replaceMask = `$1<strong>$2</strong>$3`;
return text.replace(regexp, replaceMask);
First I get the exact word which is either before/after some whitespace or a word boundary, and then I replace it with the same whitespace (if any) and word, except the word is wrapped in a <strong> tag.
Here is a version I came up with if you want to style words or individual characters at their index in react/javascript.
replaceAt( yourArrayOfIndexes, yourString/orArrayOfStrings )
Working example: https://codesandbox.io/s/ov7zxp9mjq
function replaceAt(indexArray, [...string]) {
const replaceValue = i => string[i] = <b>{string[i]}</b>;
indexArray.forEach(replaceValue);
return string;
}
And here is another alternate method
function replaceAt(indexArray, [...string]) {
const startTag = '<b>';
const endTag = '</b>';
const tagLetter = i => string.splice(i, 1, startTag + string[i] + endTag);
indexArray.forEach(tagLetter);
return string.join('');
}
And another...
function replaceAt(indexArray, [...string]) {
for (let i = 0; i < indexArray.length; i++) {
string = Object.assign(string, {
[indexArray[i]]: <b>{string[indexArray[i]]}</b>
});
}
return string;
}
Above solutions are great, but are limited! Imagine a test scenerio where you want to match case insensitive query in a string and they could be multiple matches.
For example
Query: ma
String: The Amazing Spiderman
Expected Result: The Amazing Spiderman
For above scenerio, use this:
const boldMatchText = (text,searchInput) => {
let str = text.toLowerCase();
const query = searchInput.toLowerCase();
let result = "";
let queryLoc = str.indexOf(query);
if (queryLoc === -1) {
result += text;
} else
do {
result += ` ${text.substr(0, queryLoc)}
<b>${text.substr(queryLoc, query.length)}</b>`;
str = str.substr(queryLoc + query.length, str.length);
text = text.substr(queryLoc + query.length, str.length);
queryLoc = str.indexOf(query);
} while (text.length > 0 && queryLoc !== -1);
return result + text;
};

How to extract value between # and space in textarea value

I have the following textarea code.
<textarea id="message" name="message"></textarea>
I need to get the value of the textarea and track the message content and extract out keywords that is hashed (#).
Example if the message is as below
This is my message #message #lol #haha
When i click on submit button. The keywords that i should get is 'lol and 'haha' and 'message'.
I am using jquery. Can anyone give me some advices on how to go about doing so?
As per comment, split at whitespaces, then uses Array.prototype.reduce by checking first character.
Javascript
var message = "This is my message #message #lol #haha";
var wanted = message.split(/\s/).reduce(function (previous, word) {
if (word.charAt(0) === "#") {
previous.push(word.slice(1));
}
return previous;
}, []).join(" ");
console.log(wanted);
Output
message lol haha
On jsfiddle
Alternatively using Array.prototype.filter and Array.prototype.map
Javascript
var message = "This is my message #message #lol #haha";
var wanted = message.split(/\s/).filter(function (word) {
return word.charAt(0) === "#";
}).map(function (word) {
return word.slice(1);
}).join(" ");
console.log(wanted);
On jsfiddle
Note: all of the above Array methods require a shim on pre ECMA5 browsers, available on their respective MDN pages or the use of es5_shim
Other alternatives, if you so desired, would be to use Array.prototype.forEach (which would require a shim), for or while to perform the looping of elements and Array.prototype.slice and Array.prototype.push the relevant ones.
Use a RegExp like /(?:\s|^)#([^\s]+)/g with String.prototype.match, i.e. space or start of line, then #, then non-space.
var m = 'This is my message #message #lol #haha'.match(/(?:\s|^)#([^\s]+)/g);
// [" #message", " #lol", " #haha"]
Then you can loop over these with your preferred loop, e.g. with for
var i, found = [], u;
for (var i = 0; i < m.length; ++i) {
u = m[i];
if (u.charAt(1) === '#') u = u.slice(2);
else u = u.slice(1);
found.push(u);
}
found; // ["message", "lol", "haha"]
With the same RegExp, because of how I set up the capture groups, you can strip and catch at the same time using String.prototype.replace.
var found = [], str = 'This is my message #message #lol #haha';
str = str.replace(
/(?:\s|^)#([^\s]+)/g,
function (m, keyword) {
found.push(keyword);
return '';
}
);
str; // "This is my message"
found; // ["message", "lol", "haha"]
A slight modification here could also let you capture them using replace without removing them, (return m in the function or just keep another copy of the string).
var str = "This is my message #message #lol #haha";
// or var str = $('#message').val();
var words = str.split(' ');
words = $(words).map(function (i,v) {
if(v.indexOf('#') === 0)return v.replace("#",'');
}).get();
console.log(words);
//output `==>` ["message", "lol", "haha"]
Demo ---> http://jsfiddle.net/vTpSk/2/
// You split the words with the space
var arrayContainingEveryWords = $("#message").val().split(" ");
var desiredWords = [];
// For each word within the text area
for (var i = 0; i < arrayContainingEveryWords.length; i++)
{
var word = arrayContainingEveryWords[i];
// If the first letter of the word is a #
if (word.charAt(0) == "#")
{
// Add the word (minus the #) to an array
desiredWords.push(word.slice(1));
}
}
console.log(desiredWords);
You can use one simple regular expression: \B#\w+.
var keywords = 'This is my message #message #lol #haha'.match(/\B#\w+/g);
And then remove the #s if need be:
keywords = keywords.map(function(k) { return k.substring(1); });
// or jQuery, for compatibility:
keywords = $.map(keywords, function() { return this.substring(1); });
Or use a loop:
var keywords = [];
var keyword;
var re = /\B#(\w+)/g;
while(keyword = re.exec('This is my message #message #lol #haha')) {
keywords.push(keyword[1]);
}
Use .split('#') on the string to get an array of words, then use .trim() on each item to get rid of the space.

Regex to capture Ids from text

I have the following regex where I am trying to capture the Ids of each start comment. But for some reason I am only able to capture the first one. It won't grab the Id of the nested comment. It only prints 1000 to the console. I am trying to get it to capture both 1000 and 2000. Can anyone spot the error in my regex?
<script type="text/javascript">
function ExtractText() {
var regex = /\<!--Start([0-9]{4})-->([\s\S]*?)<!--End[0-9]{4}-->/gm;
var match;
while (match = regex.exec($("#myHtml").html())) {
console.log(match[1]);
}
}
</script>
<div id="myHtml">
<!--Start1000-->Text on<!--Start2000-->the left<!--End1000-->Text on the right<!--End2000-->
</div>
Based on Mike Samuel's answer I updated my JS to the following:
function GetAllIds() {
var regex = /<!--Start([0-9]{4})-->([\s\S]*?)<!--End\1-->/g;
var text = $("#myHtml").html();
var match;
while (regex.test(text)) {
text = text.replace(
regex,
function (_, id, content) {
console.log(id);
return content;
});
}
}
In
<!--Start1000-->Text on<!--Start2000-->the left<!--End1000-->Text on the right<!--End2000-->
the "1000" region overlaps the "2000" region, but the exec loop only finds non-overlapping matches since each call to exec with the same regex and string starts at the end of the last match. To solve this problem, try
var regex = /<!--Start([0-9]{4})-->([\s\S]*?)<!--End\1-->/g;
for (var s = $("#myHtml").html(), sWithoutComment;
// Keep going until we fail to replace a comment bracketed chunk
// with the chunk minus comments.
true;
s = sWithoutComment) {
// Replace one group of non-overlapping comment pairs.
sWithoutComment = s.replace(
regex,
function (_, id, content) {
console.log(id);
// Replace the whole thing with the body.
return content;
});
if (s === sWithoutComment) { break; }
}
You can use grouping and then another regexp:
var regex = /(<!--Start)([0-9]{4})/ig;
var str = document.getElementById('myHtml').innerHTML;
var matches = str.match(regex);
for(var i=0;i<matches.length;i++){
var m = matches[i];
var num = m.match(/(\d+)/)[1];
console.log(num);
}

Categories

Resources