Applying an expression depending on a condition in a loop - c

I guess this question surely has been asked several times, but I couldn't find anything.
I have a function that depends on an argument (caseset) which can be of two different kinds. Depending on its nature, in a loop I need to perform an operation rather than another. Since the nature of the object is known at the beginning, it appears to me inefficient and inelegant to have an if statement each time in the loop. Ideally, I'd apply the right expression each time and choose it atop of the loop. Here is a code to have an idea of what I'm after.
SEXP doSomething(SEXP anObject, SEXP caseset, SEXP isMat) {
/*
* here anObject is an external pointer to a C structure,
* caseset is either a character matrix or a data.frame made of character columns.
*/
int i,j,nrow,ncol;
int isMatrix = LOGICAL(isMat)[0];
const char *field;
/*
* Determine the number of rows and columns in each case
*/
if (isMatrix) {
ncol = length(VECTOR_ELT(getAttrib(caseset,R_DimNamesSymbol),1));
nrow = length(caseset)/ncol;
} else {
ncol = length(caseset);
nrow = length(VECTOR_ELT(caseset,0));
}
for (i=0;i<nrow;i++) {
for (j=0;j<ncol;j++) {
if (isMatrix) {
field = CHAR(STRING_ELT(caseset,j*nrow+i));
} else {
field = CHAR(STRING_ELT(VECTOR_ELT(caseset,j),i));
}
/*
* Do stuff involving field and anObject
*/
}
}
return result;
}
I'm writing a C function callable from R. I'm passing R objects (the SEXP types). The caseset object can be either a matrix or a data.frame. I'm processing a row at the time and since the two objects stores their element very differently, to get the (i,j) value of the table you have to move differently. Note the if condition stated each time (which for every call of doSomething will have the same result). The rest of the function is pretty long.
I can certainly:
move the if condition outside the loop and rewrite two identical blocks of code (except for one line) depending on the value of isMatrix;
write two almost identical functions and "dispatch" the right one depending on the nature of caseset.
However, both the above options look inelegant to me. I'd prefer to have something that let you apply the right line in the loop without checking the condition each time and without having to rewrite twice code.

C is not exactly well known for elegance. Other languages might allow you to use some sort of iterator perhaps. Checking isMatrix twice is not bad. But of course you might need to check more times or maybe support more types.
Consider using two internal functions based on isMat:
SEXP doSomething(SEXP anObject, SEXP caseset, SEXP isMat) {
/*
* here anObject is an external pointer to a C structure,
* caseset is either a character matrix or a data.frame made of character columns.
*/
return LOGICAL(isMat)[0] ? doSomethingMatrix(anObject,caseset) : doSomethingFrame(anObject,caseset);
}
static doSomethingMatrix(SEXP anObject, SEXP caseset) {
int i,j,nrow,ncol;
const char *field;
ncol = length(VECTOR_ELT(getAttrib(caseset,R_DimNamesSymbol),1));
nrow = length(caseset)/ncol;
for (i=0;i<nrow;i++) {
for (j=0;j<ncol;j++) {
field = CHAR(STRING_ELT(caseset,j*nrow+i));
// Share the long processing code between the two functions
doStuffField(anObject,field);
}
}
return result;
}

You could use an array of function pointers.
For example, to program a calculator, instead of:
if (c == '+')
return (a + b);
elif (c == '-')
return (a - b);
...
You could do something like:
char *op = {'+', '-', '/', '*', '%', 'whatever you want', NULL};
for (int i=0, op[i] && op[i] != c, i++};
if (op[i])
return (my_function_ptr[i](a, b));
And it would call the function number 'i' in the array.

Related

How to include last element in loops in C?

This is a general issue I've run into, and I've yet to find a solution to it that doesn't feel very "hack-y". Suppose I have some array of elements xs = {a_1, a_2, ..., a_n}, where I know some x is in the array. I wish to loop through the array, and do something with each element, up to and including the element x. Here's a version that does almost that, except it leaves out the very last element. Note that in this example the array happens to be a sorted list of integers, but in the general case this might not necessarily be true.
int xs[] = {1,2,3,4,5};
for (int i = 0; xs[i] != 4; i++) {
foo(xs[i]);
}
The only solutions I've seen so far are:
Just add a final foo(xs[i]); statement after the for-loop. This is first of all ugly and repetitious, especially in the case where foo is not just a function call but a list of statements. Second, it requires i to be defined outside the scope of the for-loop.
Manually break the loop, with an if-statement inside an infinite loop. This again seems ugly to me, since we're not really using the for and while constructs to their full extent. The problem is almost archetypal of what you'd use a for-loop for, the only difference is that we just want it to go through the loop one more time.
Does anyone know of a good solution to this problem?
In C, the for loop is a "check before body" operation, you want the "check after body" variant, a do while loop, something like:
int xs[] = {1,2,3,4,5};
{
int i = 0;
do {
foo(xs[i]);
} while (xs[i++] != 4);
}
You'll notice I've enclosed the entire chunk in its own scope (the outermost {} braces). This is just to limit the existence of i to make it conform more with the for loop behaviour.
In terms of a complete program showing this, the following code:
#include <stdio.h>
void foo(int x) {
printf("%d\n", x);
}
int main(void) {
int xs[] = {1,2,3,4,5};
{
int i = 0;
do {
foo(xs[i]);
} while (xs[i++] != 4);
}
return 0;
}
outputs:
1
2
3
4
As an aside, like you, I'm also not that keen of the two other solutions you've seen.
For the first solution, that won't actually work in this case since the lifetime of i is limited to the for loop itself (the int in the for statement initialisation section makes this so).
That means i will not have the value you expect after the loop. Either there will be no i (a compile-time error) or there will be an i which was hidden within the for loop and therefore unlikely to have the value you expect, leading to insidious bugs.
For the second, I will sometimes break loops within the body but generally only at the start of the body so that the control logic is still visible in a single area. I tend to do that if the for condition would be otherwise very lengthy but there are other ways to do this.
Try processing the loop as long as the previous element (if available) is not 4:
int xs[] = {1,2,3,4,5};
for (int i = 0; i == 0 || xs[i - 1] != 4; i++) {
foo(xs[i]);
}
This may not be a direct answer to the original question, but I would strongly suggest against making a habit of parsing arrays like that (it's like a ticking bomb waiting to explode at a random point in time).
I know you said you already know x is a member of xs, but when it is not (and this can accidentally happen for a variety of reasons) then your loop will crash your program if you are lucky, or it will corrupt irrelevant data if you are not lucky.
In my opinion, it is neither ugly nor "hacky" to be defensive with an extra check.
If the hurdle is the seemingly unknown length of xs, it is not. Static arrays have a known length, either by declaration or by initialization (like your example). In the latter case, the length can be calc'ed on demand within the scope of the declared array, by sizeof(arr) / sizeof(*arr) - you can even make it a reusable macro.
#define ARRLEN(a) (sizeof(a)/sizeof(*(a)))
...
int xs[] = {1,2,3,4,5};
/* way later... */
size_t xslen = ARRLEN(xs);
for (size_t i=0; i < xslen; i++) {
if (xs[i] == 4) {
foo( xs[i] );
break;
};
}
This will not overrun xs, even when 4 is not present in the array.
EDIT:
"within the scope of the declared array" means that the macro (or its direct code) will not work on an array passed as a function parameter.
// This does NOT work, because sizeof(arr) returns the size of an int-pointer
size_t foo( int arr[] ) {
return( sizeof(arr)/sizeof(*arr) );
}
If you need the length of an array inside a function, you can pass it too as a parameter along with the array (which actually is just a pointer to the 1st element).
Or if performance is not an issue, you may use the sentinel approach, explained below.
[end of EDIT]
An alternative could be to manually mark the end of your array with a sentinel value (a value you intentionally consider invalid). For example, for integers it could be INT_MAX:
#include <limits.h>
...
int xs[] = {1,2,3,4,5, INT_MAX};
for (size_t i=0; xs[i] != INT_MAX; i++) {
if (xs[i] == 4) {
foo( xs[i] );
break;
};
}
Sentinels are quite common for parsing unknown-length dynamically-allocated arrays of pointers, with the sentinel being NULL.
Anyway, my main point is that preventing accidental buffer overruns probably has a higher priority compared to code prettiness :)

How to test the return value from a function against multiple values without storing into a variable

How could I achieve something like this ...
int main(void)
{
if (f(x) == (a || b))
{
puts("Success");
}
return (0);
}
This would print Success if the return of f(x) is equal to a or b.
I know it is possible to store it in a variable but my question is:
"Could something like this be done by calling the f(x) function only once without using a variable?"
Edit 1: I'm not allowed to use the switch statement for this assignment
Edit 2: Could I set a range with only one expression like this?
if ( 2 < f(x) < 5)
Would this be valid (return type is int)?
how to test for multiple return values from a function called once without storing into a variable (?)
Not really, but with some restrictions let us abuse C and assume a, b and f() return a character.
1Form a character array made up of a and b and search it using memchr(). Inspired by #David C. Rankin (It does not store the result of f() in a variable, but does call a function)
int main(void) {
// v-------------v compound literal
if (memchr((char [2]){a,b}, f(x), 2)) {
puts("Success");
}
return 0;
}
I see OP added "return type is int" - Oh well.
if ( 2 < f(x) < 5) is valid code, but is does not do what OP wants.
It is like if ( (2 < f(x)) < 5) which compares f(x) with 2 and results in 0 or 1, which is always less than 5.
Tough crowd tonight, so how about the below. Needs a bit of extension math for int overflow`, but is close.
abs(2*f(x) - (a+b)) == abs(a-b)
1 Not serious code suggestions for production code - use a temporary.
This can obviously be done using a switch statement. Another way would be calling a function returning true or false with the first function value as input, another way could be a jump table or even > or bit checking using binary operators depending on a and b values (very common for testing multiple bit flags at once).
But really you shouldn't care about using or not using a variable in such cases. Current compilers are quite good putting temporary variables like that in registers.
EDIT: given the constraints, the most likely solution is using some bit fu, but it fully depends of values of a and b and c, etc. The common way is using powers of two as values to check. Then you can check a set of values in only one operation.
exemple: a = 1, b = 2, c = 4
if (f(x) & (1+2+4)) {...}
checks if we have a or b or c or a superposition of these values.
C language does not such constructs. You need do save the result of the function or/and both a & b.
Of course you can:
int compare(int a, int b, int f)
{
if(a == f || b == f) { puts("Success"); return 0;}
return -1;
}
int f(int x)
{
return x * x;;
}
int main()
{
compare(5,8,f(3));
}
but of course it saves all the values as the functions parameters.

How to do static code logical analysis with AST tree or other tool?

void f1(char *s)
{
s[20] = 0;
}
void f2()
{
char a[10];
if (x + y == 2) {
f1(a);
}
}
Cppcheck will report this message:
Array 'a[10]' index 20 out of bounds
How could Cppcheck get the connection between ‘a’ in f2 and ‘s’ in f1?
I have built AST tree, But It only supplies information of each symbol, and give little information to me on the logical relationship of symbols.
How could computer know ‘a’ in f2 and ‘s’ in f1 are the same thing?
As I know, we have to take so many situations into consideration, such as:
void f1(char *s)
{
char str_arry[30];
s= str_arry;
s[20] = 0;
}
In this case 's' and 'a' are not the same things.
I don't know how exactly Cppcheck works but I'll tell you how to solve this problem in general. There are two main approaches to the analysis of interrelated functions.
In the first case, when an analyzer meets function call it starts analyzing its body considering value of factual arguments transmitted through the function. This happens naturally only if it is known which values are transmitted to the function. This refers to: an exact value, a range, a set of values, null/non-null pointer, etc. The complexity of the transmitted information depends on the analyzer sophistication. For example, it can start analyzing the function body knowing that two of the transmitted pointers refer to the same array.
It's an excellent accurate approach. But there's a serious problem. The analyzers based on this concept are very slow. They have to analyze functions bodies with different input data sets over and over again. The functions in turn call other ones and so on. And at some point the "inside" analysis has to be stopped which, in practice, makes this approach not that accurate and excellent as it might seem in theory.
There's a second approach. It's based on automatic function annotations. The thing is, when analyzing functions the information on how its arguments are used and which values they can't take is being gazed. Let's consider the simple example that I gave in the article called 'Technologies used in the PVS-Studio code analyzer for finding bugs and potential vulnerabilities'.
int Div(int X)
{
return 10 / X;
}
void Foo()
{
for (int i = 0; i < 5; ++i)
Div(i);
}
An analyzer recognizes that X variable is used in Div function as a divider. Based on it, a special Div function annotation is created automatically. Then it takes into account the fact that a range of [0..4] values is transmitted to the function as the X argument. The analyzer concludes that the division by zero should appear.
This approach is more crude and not that accurate as the first one. But it is very fast and allows to create strong correlations between big amount of functions with no loss of productivity.
It can be much more complicated in practice. For example, the PVS-Studio analyzer uses the second approach as the main one but not always. Sometimes when dealing with template functions we analyze them once more (the first approach). In other words, we use a combined approach to maintain the balance between the depth and speed of analysis.
In order to analyze the possible sources of some value, it's a good idea to turn all variables into immutables by introducing a new symbol whenever the original was changed and using the new symbol for all following occurences (the original symbol won't be used after the point where it was re-assigned in the original code).
Consider the following code:
// control flow block 1
int i = 1;
if (some_condition()) {
// control flow block 2
i = 2;
}
// control flow block 3
int j = i;
With the control flow graph
[1]
| \ <- if (some_condition())
| [2]
| / <- join of control flow after the if block ends
[3]
You could write a list of all symbols that are alive (have a value that is used anywhere later in the control flow graph) at the entry and exit point of a block in the control flow graph:
[1] entry: nothing; exit: i
[2] entry: nothing; exit: i
[3] entry: i; exit: i, j (I assume i, j are re-used after the end of this example)
Notice that [2] entry is empty, since i is never read and always written within block [2]. The problem with this representation is, that i is in the exit list of all blocks but it has different possible values for each block.
So, lets introduce the immutable symbols in pseudo-code:
// control flow block 1
i = 1;
if (some_condition()) {
// control flow block 2
i_1 = 2;
}
// control flow block 3
// join-logic of predecessor [1] and [2]
i_2 = one_of(i, i_1);
j = i_2;
Now every variable is coupled exactly to its first (and only) assignment. Meaning, a dependency graph can be constructed by analyzing the symbols that are involved in an assignment
i -> i_2
i_1 -> i_2
i_2 -> j
Now in case there is any constraint on the allowed value of j, a static checker could require that all predecessors of j (namely i_2, in turn originating from i and i_1), satisfy this requirement.
In case of function calls, the dependency graph would contain an edge from every calling argument to the corresponding parameter in the function definition.
Applying this to your example is straight forward if we only focus on the array variable and ignore changes to the array content (I'm not quite sure to what extent a static checker would track the content of individual array items in order to find danger down the road):
Example 1:
void f1(char *s)
{
s[20] = 0;
}
void f2()
{
char a[10];
if (x + y == 2) {
f1(a);
}
}
Transforms to
f1(s)
{
s[20] = 0;
}
f2()
{
a = char[10];
if (x + y == 2) {
call f1(a);
}
}
With dependency graph including the passed arguments via function call
a -> s
So it's immediately clear that a has to be considered for the static analysis of the safety of s[20].
Example 2:
void f1(char *s)
{
char str_arry[30];
s= str_arry;
s[20] = 0;
}
Transforms to
f1(s)
{
// control flow block 1
str_arry = char[30];
s_1 = str_arry;
s_1[20] = 0;
}
With dependency graph
str_arry -> s_1
So it's immediately clear that the only value to be considered for the static analysis of the safety of s_1[20] is str_arry.
How could Cppcheck get the connection between ‘a’ in f2 and ‘s’ in f1?
They are definitely not the same. One of the following can happen:
You pass a to the function, and CPPcheck continues to remember the size of a, even though you access it with the formal parameter s.
You have to keep in mind that static analysis tools and compilers work differently, with different purposes in mind. Static analysis tools were crated EXACTLY for the purpose of catching things like you presented in your question.
In your second example you have:
s= str_arry;
which removes the connection between s and a.

Find steps to find given value of index

I am new to SO - I have a question which I was asked in interview and which for life of me I am not able to wrap my head around. I can solve it with while/for loop but interviewer specifically asked not to use them I even discussed with few friends of mine but unable to solve it. If someone can provide pointers.
Question is:
for given array
s[] = {5,1,0,4,2,3}
length of array is not given.
If length of array is 5 content
is guaranteed to be between 0 to 5.
There is no repetition of
numbers.
Sample example length(s, 3)
- a[3] = 4 , a[4] = 2, a[2] = 0, a[0] = 5, a[5] =3 returns length of 4 .
For given condition write subroutine int length (s, 3) - to find the number of steps it takes to find given value -
Additional conditions
You cannot use any loop statements like for, while and so on -
You cannot use any global or static variables.
You cannot call other routines inside this routine
You cannot modify given function parameters - it stays length (s, n) only
You cannot change original array too
Alternative solution that does not modify the array at all, but hides an extra parameter inside top 16 bits of x:
int length(int *s, int x){
int start = (x >> 16) - 1;
if (start < 0)
start = x;
if (s[x] == start)
return 0;
return 1 + length(s, ((start + 1) << 16) + s[x]);
}
This will fail if there are too many elements in the array, but I suspect any other recursive solution is likely to hit a stack overflow by that point in any case.
I think I found the answer eventually no I didnt crack it but found it online :) .. Here is the solution
int length(int * s, int x){
if(s[x] < 0){
return -1;
}
else{
s[x] = -s[x];
int len = length(s, -s[x]);
s[x] = -s[x];
return len + 1;
}
}
i don't think it contradicts with any of your conditions. i just didn't use the array as a parameter (that isn't a problem actually, you can modify it yourself)
int s[] = {5,1,0,4,2,3};
bool col[100]; ///to check cycle
int rec(int n)
{
if(col[n])return 0;
col[n]=true;
int sum=0;
sum = 1+rec(s[n]);
return sum;
}
The interviewer is probing your understanding of algorithms and programming paradigms, trying to understand your training, background, and depth. The interviewer has a challenging task; identifying capable developers with minimal evidence. Thus the interviewer presents a constructed problem that (they hope) elicits the desired knowledge (does candidate X know how to solve problem Y, or understand concept Z) perhaps because the interviewer believes the desired answer indicates the candidate knows the expected body of knowledge.
Modern languages provide several repetition structures (commands, statements), some which pre-test (check condition before entering statement-block), and some which post-test (check condition after performing statement block at least once). Here are examples,
Pre-test
while(condition) statement-block
for(initializer;condition;step) statement-block
Post-test
do statement-block while(condition)
repeat statement-block until(condition)
do statement-block until(condition)
These can all be written as conditional (choice) structures with branching (goto),
Pre-test
label:
if(condition)
statement-block;
goto label;
else
nil;
endif
Post-test
label:
statement-block;
if(condition)
goto label;
endif
You can also use recursion, where you call the same function as long as condition holds (or until condition met, depending upon positive or negative logic),
Pre-test
function recurse(args)
if(condition)
statement-block
recurse(revised args);
endif
return
end #function
Post-test
function recurse(args)
statement-block
if(condition)
recurse(revised args);
endif
return;
end
You would learn about recursion in an algorithms, or perhaps a computability course. You would learn about conditional branching in a compiler, high performance computing, or systems class. Your compiler course might examine techniques for detecting 'tail-recursion', and how to rewrite the function call into a loop.
Here is the problem, restated,
given array, s[] = {5,1,0,4,2,3}
array length unknown
content between [0 .. length], not repeated, no duplicates
write subroutine which provides the number of steps to find given value
That is,
int length( array s, int member ) --> position
Examine the conditions (constraints) on the problem,
Array length unknown - Solution must work for variable range of inputs
Cannot use loop statements (for, while, etc) - This suggests either the interviewer wants conditional branch or recursion.
Cannot use global or static variables - Does this suggest interviewer wants a recursive/functional-programming solution? Conditional-branch also provides this.
Cannot call other routines inside this routine - Does interviewer mean functions other than same function, or call any function (what does interviewer mean by 'other').
Cannot modify function parameters, stays length(s,n) - Declaring local (stack) variables is allowed. This could mean pass by value, make a local copy, etc. But not destructive modifications.
Cannot change original array - Definitely no destructive modifications. Possible 'hint' (ok to make local copy?), or further indication that you should use conditional-branch?
Here are two solutions, and a test driver (note, I have named them lengthi, iterative, and lengthr, recursive).
#include <stdio.h>
/* conditional branch */
int lengthi( int s[], int member )
{
int position=0;
AGAIN:
if( s[position] == member ) return(position);
++position;
goto AGAIN;
return(-1);
}
/* recursive */
int lengthr( int s[], int member )
{
if( s[0] == member ) return(0);
return( 1+length(s+1,member) );
}
int
main(int argc,char* argv[])
{
int s1[] = {0,1,2,3,4,5,6,7,8,9};
int s2[] = {1,2,3,4,9,8,7,6,0,5};
int s3[] = {2,4,6,8,0,1,3,5,7,9};
printf("%d at %d\n",3,lengthr(s1,3));
printf("%d at %d\n",3,lengthr(s2,3));
printf("%d at %d\n",3,lengthr(s3,3));
printf("%d at %d\n",3,lengthi(s1,3));
printf("%d at %d\n",3,lengthi(s2,3));
printf("%d at %d\n",3,lengthi(s3,3));
}
Since we are supposed to find the number of steps (iterations, function calls), that is asking for the ordinal position in the list, not the C index (zero based) position.
This is an interview question, and not a programming problem (per se), so probably better suited for the Programmers.stackexchange site. I might give the interviewer an entertaining answer, or their desired answer.

Is it possible to use a for loop to change a variable name in C?

This is a generic question, so there is no actual code that I am trying to troubleshoot. But what I want to know is, can I use a for loop to change the name of a variable in C? For instance, if I have part1, part2, part3, part..., as my variable names; is there a way to attach it to my loop counter so that it will increment with each passing? I toyed around with some things, nothing seemed to work.
In C, you can't 'change the name of the loop variable' but your loop variable does not have to be determined at compile time as a single variable.
For instance, there is no reason in C why you can't do this:
int i[10];
int j;
j = /* something */;
for (i[j] = 0 ; i[j] < 123 ; i[j]++)
{
...
}
or event supply a pointer
void
somefunc f(int *i)
{
for (*i = 0; *i<10; *i++)
{
...
}
}
It's not obvious why you want to do this, which means it's hard to post more useful examples, but here's an example that uses recursion to iterate a definable number of levels deep and pass the innermost function all the counter variables:
void
recurse (int levels, int level, int max, int *counters)
{
if (level < levels)
{
for (counters[level] = 0;
counters[level] < max;
counters[level]++)
{
recurse (levels, level+1, max, counters);
}
return;
}
/* compute something using counters[0] .. counters[levels-1] */
/* each of which will have a value 0 .. max */
}
Also note that in C, there is really no such thing as a loop variable. In a for statement, the form is:
for ( A ; B ; C ) BODY
Expression A gets evaluated once at the start. Expression B is evaluated prior to each execution of BODY and the loop statement will terminate (and not execute BODY) if it evaluates to 0. Expression C is evaluated after each execution of BODY. So you can if you like write:
int a;
int b = /* something */;
int c = /* something */;
for ( a=0; b<5 ; c++ ) { ... }
though it will not usually be a good idea.
The answer is, as #user2682768 correctly remarked, an array. I am not sure whether you are aware of that and consciously do not want to use an array for some reason; your little experience doesn't give me enough information. If so, please bear with me.
But you'll recognize the structural similarity between part1, part2, part3... and part[1], part[2], part[3]. The difference is that the subscript of an array is variable and can be changed programmatically, while the subscript part of a variable name cannot because it is burned in at compile time. (Using macros introduces a meta compiling stage which lets you programmatically change the source before actually compiling it, but that's a different matter.)
So let's compare code. Say you want to store the square of a value in a variable whose name has the value as a suffix. You would like to do something like
int square1, square2, square3;
int i;
for(i=1; i<=3; i++)
{
square/i/ = i*i; /* /i/ to be replaced by suffix "i".
}
With arrays, that changes to
int square[4];
int i;
for(i=1; i<=3; i++)
{
/* the (value of) i is now used as an index in the array.*/
square[i] = i*i;
}
Your idea to change the variable name programmatically implies that all variables have the same type (because they would have to work in the same piece of code, like in my example). This requirement makes them ideally suited for array elements which all have to be of the same type. If that is too restrictive, you need to do something fancier, like using unions (but how do you know what's in it at any given moment? It's almost as if you had different variables to begin with), void pointers to untyped storage or C++ with templates.
In C You cannot append to a variable name an expression that expands to a number and use it as a sort of suffix to access different variables that begin in the same way.
The closest you can get, is to "emulate" this behaviour using a switch construct, but there wouldn't be much of a point to try to do this.
What you asked for is more suited to scripting languages.

Resources