Get attribute or elements from page by script in nightwatch - nightwatch.js

I need a check that class elements was ui-state-active.
class="ui-state-default ui-state-active" href="#">15</a>
I am trying to using all methods and don't undestand how to write a code:
.perform(function () {
var arrAttr = [];
var arrCssProp = [];
var arrValue= [];
for (i = 1; i < 8; i++) {
for (j = 1; j < 7; j++) {
browser.useXpath();
browser.getCssProperty('//*[#id="ui-datepicker-div"]/table/tbody/tr[' + i + ']/td[' + j + ']', '.ui-state-default', function (result) {
arrCssProp[j, i] = result.value;
});
browser.getAttribute('//*[#id="ui-datepicker-div"]/table/tbody/tr[' + i + ']/td[' + j + ']', '.ui-state-default', function (result) {
arrAttr[j, i] = result.value;
});
browser.getValue('//*[#id="ui-datepicker-div"]/table/tbody/tr[' + i + ']/td[' + j + ']', '.ui-state-default', function (result) {
arrValue[j, i] = result.value;
});
browser.useCss();
writeLogLine('arrAttr:' + i + "|" + j + ' :' + arrAttr);
console.log('arrAttr:' + i + "|" + j + ' :' + arrAttr);
writeLogLine('arrCssProp:' + i + "|" + j + ' :' + arrCssProp);
console.log('arrCssProp:' + i + "|" + j + ' :' + arrCssProp);
writeLogLine('arrValue:' + i + "|" + j + ' :' + arrValue);
console.log('arrValue:' + i + "|" + j + ' :' + arrValue);
}
}
})

To get the attribute of class, you can write similar code
browser.getAttribute(pageObject.getElement('#ui'), "class", function (result) {
if (result.value.indexOf("ui-state-active")!=-1) {
console.log('class name:' + result.value);
}
else { console.log('class name:' + result.value); }});
You can use any locator strategy. To use CSS strategy based on class name, use .ui-state-default along with tagname.
Hope this helps.

Like in Rohit's example, if you want to use an attribute value, all the commands that rely on it need to be inside the callback. Doing arrCssProp[j, i] = result.value; won't work, since that value will disappear as soon as you exit the callback.
For more info, check out https://github.com/nightwatchjs/nightwatch/wiki/Understanding-the-Command-Queue

Related

Generate all valid combinations of N pairs of parentheses

UPDATE (task detailed Explanation):
We have a string consist of numbers 0 and 1, divided by operators |, ^ or &. The task is to create all fully parenthesized expressions. So the final expressions should be divided into "2 parts"
For example
0^1 -> (0)^(1) but not extraneously: 0^1 -> (((0))^(1))
Example for expression 1|0&1:
(1)|((0)&(1))
((1)|(0))&(1)
As you can see both expressions above have left and write part:
left: (1); right: ((0)&(1))
left: ((1)|(0)); right: (1)
I tried the following code, but it does not work correctly (see output):
// expression has type string
// result has type Array (ArrayList in Java)
function setParens(expression, result) {
if (expression.length === 1) return "(" + expression + ")";
for (var i = 0; i < expression.length; i++) {
var c = expression[i];
if (c === "|" || c === "^" || c === "&") {
var left = expression.substring(0, i);
var right = expression.substring(i + 1);
leftParen = setParens(left, result);
rightParen = setParens(right, result);
var newExp = leftParen + c + rightParen;
result.push(newExp);
}
}
return expression;
}
function test() {
var r = [];
setParens('1|0&1', r);
console.log(r);
}
test();
code output: ["(0)&(1)", "(0)|0&1", "(1)|(0)", "1|0&(1)"]
Assuming the input expression is not already partially parenthesized and you want only fully parenthesized results:
FullyParenthesize(expression[1...n])
result = {}
// looking for operators
for p = 1 to n do
// binary operator; parenthesize LHS and RHS
// parenthesize the binary operation
if expression[p] is a binary operator then
lps = FullyParenthesize(expression[1 ... p - 1])
rps = FullyParenthesize(expression[p + 1 ... n])
for each lp in lps do
for each rp in rps do
result = result U {"(" + lp + expression[p] + rp + ")"}
// no binary operations <=> single variable
if result == {} then
result = {"(" + expression + ")")}
return result
Example: 1|2&3
FullyParenthesize("1|2&3")
result = {}
binary operator | at p = 2;
lps = FullyParenthesize("1")
no operators
result = {"(" + "1" + ")"}
return result = {"(1)"}
rps = Parenthesize("2&3")
result = {"2&3", "(2&3)"}
binary operator & at p = 2
lps = Parenthesize("2")
no operators
result = {"(" + "2" + ")"}
return result = {"(2)"}
rps = Parenthesize("3")
no operators
result = {"(" + "3" + ")"}
return result = {"(3)"}
lp = "(2)"
rp = "(3)"
result = result U {"(" + "(2)" + "&" + "(3)" + ")"}
return result = {"((2)&(3))"}
lp = "(1)"
rp = "((2)&(3))"
result = result U {"(" + "(1)" + "|" + "((2)&(3))" + ")"}
binary operator & at p = 4
...
result = result U {"(" + "((1)|(2))" + "&" + "(3)" + ")"}
return result {"((1)|((2)&(3)))", "(((1)|(2))&(3))"}
You will have 2^k unique fully parenthesized expressions (without repeated parentheses) given an input expression with k binary operators.

Calculate new release time for files

We have some code that checks each incoming file against 3 different criteria before processing (Not a weekend, not after 6pm, not a holiday). This being said, I need to figure out how to have it check for a half hour now (bolded part). I have tried adding a + mRelease > 30 as well as AND mRelease > 30 and both have failed. I have been altering this line
Do While (WeekDay(dRelease) = 1) OR (WeekDay(dRelease) = 7) OR (UBound(fHoliday) > -1) OR (tRelease >17)
Here is the code currently in place:
result = ""
dRelease = Now
tRelease = CStr(Hour(Now))
mRelease = CStr(Minute(Now))
aHoliday = Array("01/02/2017","01/16/2017","05/29/2017","07/04/2017","09/04/2017","10/09/2017","11/23/2017","11/24/2017","12/25/2017","12/26/2017")
dNow = CStr(DatePart("m",Date)) + "/" + CStr(DatePart("d",Date)) + "/" + CStr(DatePart("yyyy",Date))
dMonth = "0" + CStr(Month(dRelease))
dDay = "0" + CStr(Day(dRelease))
dYear = CStr(Year(dRelease))
fHoliday = Filter(aHoliday,Right(dMonth,2) + "/" + Right(dDay,2) + "/" + dYear)
'fHoliday = Filter(aHoliday,dNow)
'result = UBound(fHoliday)
'result = Left(dRelease,10)
'result = CStr(DatePart("m",Date)) + "/" + CStr(DatePart("d",Date)) + "/" + CStr(DatePart("yyyy",Date))
'While release date is a weekend, or release date is a holiday
Do While (WeekDay(dRelease) = 1) OR (WeekDay(dRelease) = 7) OR (UBound(fHoliday) > -1) OR (tRelease >17)
'increase release date by 1
dRelease = dRelease + 1
'result = dRelease
'check for holiday
dMonth = "0" + CStr(Month(dRelease))
dDay = "0" + CStr(Day(dRelease))
dYear = CStr(Year(dRelease))
'fHoliday = Filter(aHoliday,Left(dRelease,10))
fHoliday = Filter(aHoliday,Right(dMonth,2) + "/" + Right(dDay,2) + "/" + dYear)
tRelease = 00
Loop
'Format the release date to the Esker deferred date/time standard.
dMonth = "0" + CStr(Month(dRelease))
dDay = "0" + CStr(Day(dRelease))
dYear = CStr(Year(dRelease))
dtCurrent = Right(dMonth,2) + "/" + Right(dDay,2) + "/" + dYear
If dRelease > Now Then
tRelease = "00:" + mRelease
Else
tRelease = CStr(Hour(Now)) + ":" + CStr(Minute(Now))
End If
result = dtCurrent + " " + tRelease
Change this:
Do While (WeekDay(dRelease) = 1) OR (WeekDay(dRelease) = 7) OR (UBound(fHoliday) > -1) OR (tRelease >17)
...
Loop
into this:
If (WeekDay(dRelease) = 1) Or (WeekDay(dRelease) = 7) Or (UBound(fHoliday) > -1) Or (Time > CDate("16:30")) Then
...
End If

Simplifying Code with For or While to Export Various Variable of a Table

Is there a way to simplify this code?
Basically is a script to export a table from Google Sheets and send it via email. But it's not a clean script, although it works.
If there is anyway of making it more simple, or instead of get all the values get the complete table and then export, that would be much more clean.
function sendFuelcount() {
var sheet = SpreadsheetApp.getActiveSpreadsheet();
sheet.setActiveSheet(sheet.getSheets()[0]);
var nom0 = sheet.getRange("A1").getValue();
var fuel0 = sheet.getRange("D1").getValue();
var line0 = nome0 + "\t\t" + fuel0;
var nom1 = sheet.getRange("A2").getValue();
var fuel1 = sheet.getRange("D2").getValue();
var data1 = sheet.getRange("C2").getValue();
var line1 = nom1 + "\t" + fuel1 + "\t\t" + "Em: " + data1;
var nom2 = sheet.getRange("A3").getValue();
var fuel2 = sheet.getRange("D3").getValue();
var data2 = sheet.getRange("C3").getValue();
var line2 = nom2 + "\t\t" + fuel2 + "\t\t" + "Em: " + data2;
var nome3 = sheet.getRange("A4").getValue();
var fuel3 = sheet.getRange("D4").getValue();
var data3 = sheet.getRange("C4").getValue();
var line3 = nome3 + "\t\t" + fuel3 + "\t\t" + "Em: " + data3;
var nome4 = sheet.getRange("A5").getValue();
var fuel4 = sheet.getRange("D5").getValue();
var data4 = sheet.getRange("C5").getValue();
var line4 = nome4 + "\t" + fuel4 + "\t\t" + "Em: " + data4;
var nome5 = sheet.getRange("A6").getValue(); //cBranco
var fuel5 = sheet.getRange("D6").getValue();
var data5 = sheet.getRange("C6").getValue();
var line5 = nome5 + "\t" + fuel5 + "\t\t" + "Em: " + data5;
var nome6 = sheet.getRange("A7").getValue();
var fuel6 = sheet.getRange("D7").getValue();
var data6 = sheet.getRange("C7").getValue();
var line6 = nome6 + "\t" + fuel6 + "\t\t" + "Em: " + data6;
var nome7 = sheet.getRange("A8").getValue();
var fuel7 = sheet.getRange("D8").getValue();
var data7 = sheet.getRange("C8").getValue();
var line7 = nome7 + "\t" + fuel7 + "\t\t" + "Em: " + data7;
var nome8 = sheet.getRange("A9").getValue();
var fuel8 = sheet.getRange("D9").getValue();
var data8 = sheet.getRange("C9").getValue();
var line8 = nome8 + "\t\t" + fuel8 + "\t\t" + "Em: " + data8;
var nome9 = sheet.getRange("A10").getValue();
var fuel9 = sheet.getRange("D10").getValue();
var data9 = sheet.getRange("C10").getValue();
var line9 = nome9 + "\t\t" + fuel9 + "\t" + "Em: " + data9;
var nome10 = sheet.getRange("A11").getValue();
var fuel10 = sheet.getRange("D11").getValue();
var data10 = sheet.getRange("C11").getValue();
var line10 = nome10 + "\t" + fuel10 + "\t\t" + "Em: " + data10;
var nome11 = sheet.getRange("A12").getValue(); //fZezere
var fuel11 = sheet.getRange("D12").getValue();
var data11 = sheet.getRange("C12").getValue();
var line11 = nome11 + "\t" + fuel11 + "\t\t" + "N.A.";
var nome12 = sheet.getRange("A13").getValue();
var fuel12 = sheet.getRange("D13").getValue();
var data12 = sheet.getRange("C13").getValue();
var line12 = nome12 + "\t" + fuel12 + "\t\t" + "Em: " + data12;
var nome13 = sheet.getRange("A14").getValue();
var fuel13 = sheet.getRange("D14").getValue();
var data13 = sheet.getRange("C14").getValue();
var line13 = nome13 + "\t\t" + fuel13 + "\t\t" + "Em: " + data13;
var nome14 = sheet.getRange("A15").getValue();
var fuel14 = sheet.getRange("D15").getValue();
var data14 = sheet.getRange("C15").getValue();
var line14 = nome14 + "\t\t" + fuel14 + "\t\t" + "Em: " + data14;
var nome15 = sheet.getRange("A16").getValue();
var fuel15 = sheet.getRange("D16").getValue();
var data15 = sheet.getRange("C16").getValue();
var line15 = nome15 + "\t" + fuel15 + "\t\t" + "Em: " + data15;
var nome16 = sheet.getRange("A17").getValue(); //ourique
var fuel16 = sheet.getRange("D17").getValue();
var data16 = sheet.getRange("C17").getValue();
var line16 = nome16 + "\t" + fuel16 + "\t\t" + "Em: " + data16;
var nome17 = sheet.getRange("A18").getValue();
var fuel17 = sheet.getRange("D18").getValue();
var data17 = sheet.getRange("C18").getValue();
var line17 = nome17 + "\t" + fuel17 + "\t\t" + "Em: " + data17;
var nome18 = sheet.getRange("A19").getValue();
var fuel18 = sheet.getRange("D19").getValue();
var data18 = sheet.getRange("C19").getValue();
var line18 = nome18 + "\t" + fuel18 + "\t\t" + "Em: " + data18;
var nome19 = sheet.getRange("A20").getValue();
var fuel19 = sheet.getRange("D20").getValue();
var data19 = sheet.getRange("C20").getValue();
var line19 = nome19 + "\t\t" + fuel19 + "\t\t" + "Em: " + data19;
var nome20 = sheet.getRange("A21").getValue();
var fuel20 = sheet.getRange("D21").getValue();
var data20 = sheet.getRange("C21").getValue();
var line20 = nome20 + "\t" + fuel20 + "\t\t" + "Em: " + data20;
var nome21 = sheet.getRange("A22").getValue();
var fuel21 = sheet.getRange("D22").getValue();
var data21 = sheet.getRange("C22").getValue();
var line21 = nome21 + "\t" + fuel21 + "\t\t" + "Em: " + data21;
var nome22 = sheet.getRange("A23").getValue();
var fuel22 = sheet.getRange("D23").getValue();
var data22 = sheet.getRange("C23").getValue();
var line22 = nome22 + "\t\t" + fuel22 + "\t\t" + "Em: " + data22;
var nome23 = sheet.getRange("A24").getValue();
var fuel23 = sheet.getRange("D24").getValue();
var data23 = sheet.getRange("C24").getValue();
var line23 = nome23 + "\t" + fuel23 + "\t\t" + "N.A.";
var nome24 = sheet.getRange("A25").getValue();
var fuel24 = sheet.getRange("D25").getValue();
var data24 = sheet.getRange("C25").getValue();
var line24 = nome24 + "\t" + fuel24 + "\t\t" + "N.A.";
var data = Utilities.formatDate(new Date(), "GMT", "dd-MMM-yyyy")
var msg = ""+line0+"\n"+line1+"\n"+line2+"\n"+line3+"\n"+line4+"\n"+line5+"\n"+line6+"\n"+line7+"\n"+line8+"\n"+line9+"\n"+line10+"\n"+line11+"\n"+line12+"\n"+line13+"\n"+line14+"\n"+line15+"\n"+line16+"\n"+line17+"\n"+line18+"\n"+line19+"\n"+line20+"\n"+line21+"\n"+line22+"\n"+line23+"\n"+line24+" \n \nEMAIL GERADO AUTOMATICAMENTE POR GROUND OPERATIONS"
MailApp.sendEmail("emails#gmail.com", "Fuel "+data+"", msg, {
name: 'Fuel Qty Auto Message'});
}

How to append click event to handsontable row/column header?

I'm trying to implement some features like excel to click row/column header to select entire row/column, I think I should append a click event to all row/column header, so I tried add code below in core.js, but it was never been trigged:
this.click = function() {
alert("Clicked!");
};
So where should I begin with?
Thanks for any help.
Implemented by myself based on Handsontable 0.9.9:
From 5e2e8f51374741432d34624eb86edce6a802bf80 Mon Sep 17 00:00:00 2001
From: Xinfeng Li <xinfli#gmail.com>
Date: Wed, 17 Jul 2013 12:04:21 +0800
Subject: [PATCH 1/1] Implement select entire row/column when click on
row/column header.
---
src/3rdparty/walkontable/src/event.js | 5 ++++
src/3rdparty/walkontable/src/settings.js | 3 +-
src/pluginHooks.js | 3 ++
src/tableView.js | 50 ++++++++++++++++++++++++++++++++
4 files changed, 60 insertions(+), 1 deletion(-)
diff --git a/src/3rdparty/walkontable/src/event.js b/src/3rdparty/walkontable/src/event.js
index e150fef..a4cbb09 100644
--- a/src/3rdparty/walkontable/src/event.js
+++ b/src/3rdparty/walkontable/src/event.js
## -17,6 +17,11 ## function WalkontableEvent(instance) {
that.instance.getSetting('onCellMouseDown', event, cell.coords, cell.TD);
}
}
+ else if (cell.TD && cell.TD.nodeName === 'TH') {
+ if (that.instance.hasSetting('onHeaderMouseDown')) {
+ that.instance.getSetting('onHeaderMouseDown', event, cell.coords, cell.TD);
+ }
+ }
else if (that.wtDom.hasClass(event.target, 'corner')) {
that.instance.getSetting('onCellCornerMouseDown', event, event.target);
}
diff --git a/src/3rdparty/walkontable/src/settings.js b/src/3rdparty/walkontable/src/settings.js
index 35eb736..b16e4cf 100644
--- a/src/3rdparty/walkontable/src/settings.js
+++ b/src/3rdparty/walkontable/src/settings.js
## -41,8 +41,9 ## function WalkontableSettings(instance, settings) {
//callbacks
onCellMouseDown: null,
+ onHeaderMouseDown: null,
onCellMouseOver: null,
-// onCellMouseOut: null,
+ //onCellMouseOut: null,
onCellDblClick: null,
onCellCornerMouseDown: null,
onCellCornerDblClick: null,
diff --git a/src/pluginHooks.js b/src/pluginHooks.js
index afcc7e2..ececdd1 100644
--- a/src/pluginHooks.js
+++ b/src/pluginHooks.js
## -37,6 +37,9 ## Handsontable.PluginHookClass = (function () {
afterSelectionEndByProp : [],
afterCopyLimit : [],
+ // Customer plugin after row/column header clicked.
+ afterHeaderClick : [],
+
// Modifiers
modifyCol : []
}
diff --git a/src/tableView.js b/src/tableView.js
index 39512c0..ded6b74 100644
--- a/src/tableView.js
+++ b/src/tableView.js
## -242,6 +242,56 ## Handsontable.TableView = function (instance) {
that.settings.afterOnCellMouseDown.call(instance, event, coords, TD);
}
},
+ onHeaderMouseDown: function (event, coords, TD) {
+ var row = coords[0];
+ var col = coords[1];
+ var rangeRowStart, rangeColStart, rangeRowEnd, rangeColEnd;
+
+ //console.log("Clicked on header[row = " + row + ", col = " + col + "], TD.innerHTML.length: " + TD.innerHTML.length);
+ if ((row == 0) && (col == -1) && (TD.innerHTML.length == 0)) {
+ // Click on left upper corner
+ // Since the row and col is same when click on left upper corner and row heder of first row,
+ // The length of current TD.innerHTML must be checked.
+ rangeRowStart = 0;
+ rangeColStart = 0;
+ rangeRowEnd = instance.countRows() - 1;
+ rangeColEnd = instance.countCols() - 1;
+ }
+ else if (row == 0) {
+ if (col >= 0) {
+ // Click on column header
+ rangeRowStart = 0;
+ rangeColStart = col;
+ rangeRowEnd = instance.countRows() - 1;
+ rangeColEnd = col;
+ } else {
+ // Click on row header of first row
+ rangeRowStart = row;
+ rangeColStart = 0;
+ rangeRowEnd = row;
+ rangeColEnd = instance.countCols() - 1;
+ }
+ }
+ else if (col == -1) {
+ // Click on row header
+ rangeRowStart = row;
+ rangeColStart = 0;
+ rangeRowEnd = row;
+ rangeColEnd = instance.countCols() - 1;
+ }
+
+ if ((rangeRowStart != undefined) && (rangeColStart != undefined) && (rangeRowEnd != undefined) && (rangeColEnd != undefined)) {
+ //console.log("Select from [" + rangeRowStart + ", " + rangeColStart + "] to [" + rangeRowEnd + ", " + rangeColEnd + "]");
+ instance.selectCell(rangeRowStart, rangeColStart, rangeRowEnd, rangeColEnd);
+ }
+
+ if (!that.settings.fragmentSelection) {
+ event.preventDefault(); //disable text selection in Chrome
+ clearTextSelection();
+ }
+
+ instance.PluginHooks.run('afterHeaderClick', event, coords, TD);
+ },
/*onCellMouseOut: function (/*event, coords, TD* /) {
if (isMouseDown && that.settings.fragmentSelection === 'single') {
clearTextSelection(); //otherwise text selection blinks during multiple cells selection
--
1.8.1.msysgit.1

4x4 Fixed point matrix multiplication doesn't work

I have this function which concatenates two matrices:
out->_11 = MAT_MUL(b->_11, a->_11) + MAT_MUL(b->_21, a->_12) + MAT_MUL(b->_31, a->_13) + MAT_MUL(b->_41, a->_14);
out->_12 = MAT_MUL(b->_12, a->_11) + MAT_MUL(b->_22, a->_12) + MAT_MUL(b->_32, a->_13) + MAT_MUL(b->_42, a->_14);
out->_13 = MAT_MUL(b->_13, a->_11) + MAT_MUL(b->_23, a->_12) + MAT_MUL(b->_33, a->_13) + MAT_MUL(b->_43, a->_14);
out->_14 = MAT_MUL(b->_14, a->_11) + MAT_MUL(b->_24, a->_12) + MAT_MUL(b->_34, a->_13) + MAT_MUL(b->_44, a->_14);
out->_21 = MAT_MUL(b->_11, a->_21) + MAT_MUL(b->_21, a->_22) + MAT_MUL(b->_31, a->_23) + MAT_MUL(b->_41, a->_24);
out->_22 = MAT_MUL(b->_12, a->_21) + MAT_MUL(b->_22, a->_22) + MAT_MUL(b->_32, a->_23) + MAT_MUL(b->_42, a->_24);
out->_23 = MAT_MUL(b->_13, a->_21) + MAT_MUL(b->_23, a->_22) + MAT_MUL(b->_33, a->_23) + MAT_MUL(b->_43, a->_24);
out->_24 = MAT_MUL(b->_14, a->_21) + MAT_MUL(b->_24, a->_22) + MAT_MUL(b->_34, a->_23) + MAT_MUL(b->_44, a->_24);
out->_31 = MAT_MUL(b->_11, a->_31) + MAT_MUL(b->_21, a->_32) + MAT_MUL(b->_31, a->_33) + MAT_MUL(b->_41, a->_34);
out->_32 = MAT_MUL(b->_12, a->_31) + MAT_MUL(b->_22, a->_32) + MAT_MUL(b->_32, a->_33) + MAT_MUL(b->_42, a->_34);
out->_33 = MAT_MUL(b->_13, a->_31) + MAT_MUL(b->_23, a->_32) + MAT_MUL(b->_33, a->_33) + MAT_MUL(b->_43, a->_34);
out->_34 = MAT_MUL(b->_14, a->_31) + MAT_MUL(b->_24, a->_32) + MAT_MUL(b->_34, a->_33) + MAT_MUL(b->_44, a->_34);
out->_41 = MAT_MUL(b->_11, a->_41) + MAT_MUL(b->_21, a->_42) + MAT_MUL(b->_31, a->_43) + MAT_MUL(b->_41, a->_44);
out->_42 = MAT_MUL(b->_12, a->_41) + MAT_MUL(b->_22, a->_42) + MAT_MUL(b->_32, a->_43) + MAT_MUL(b->_42, a->_44);
out->_43 = MAT_MUL(b->_13, a->_41) + MAT_MUL(b->_23, a->_42) + MAT_MUL(b->_33, a->_43) + MAT_MUL(b->_43, a->_44);
out->_44 = MAT_MUL(b->_14, a->_41) + MAT_MUL(b->_24, a->_42) + MAT_MUL(b->_34, a->_43) + MAT_MUL(b->_44, a->_44);
MAT_MUL looks like this:
#define MAT_MUL(o1,o2) ((GLfixed)((long)(o1)*(long)(o2))>>16)
The odd thing is that it doesn't work with fixed point values but with float values (MAT_MUL(o1,o2) (o1)*(o2) in this case). I traced the error down to this bit of code.
Any ideas? Thanks

Resources