Compare commits

...

3 Commits

Author SHA1 Message Date
Weijian Duan
27842e0590
Merge ea28bb9c62 into 495272cff9 2024-09-28 15:42:34 +08:00
Jason Klebes
495272cff9
[fortran/en] Fixed overly long comment lines (#5126)
Some checks failed
Trigger site build / deploy (push) Has been cancelled
CI / lint (push) Has been cancelled
* [haskell/de] Added missing comment line about index operator

* [fortran/en] Fixed overly long comment lines

Including minor rewording and rearranging.  A comment was added at 'subroutine'
2024-09-25 11:45:27 +02:00
weijianduan
ea28bb9c62 Update and add contents following TOML v1.0.0 spec 2024-09-10 23:54:16 +08:00
2 changed files with 291 additions and 129 deletions

View File

@ -30,7 +30,8 @@ program example ! declare a program called example.
! All declarations must come before statements and expressions. ! All declarations must come before statements and expressions.
implicit none ! prevents dynamic declaration of variables (recommended!) implicit none ! prevents dynamic declaration of variables
! Recommended!
! Implicit none must be redeclared in every function/program/module... ! Implicit none must be redeclared in every function/program/module...
! IMPORTANT - Fortran is case insensitive. ! IMPORTANT - Fortran is case insensitive.
@ -45,10 +46,14 @@ program example ! declare a program called example.
complex :: w = (0, 1) ! sqrt(-1) complex :: w = (0, 1) ! sqrt(-1)
character(len=3) :: month ! string of 3 characters. character(len=3) :: month ! string of 3 characters.
real :: array(6) ! declare an array of 6 reals. ! declare an array of 6 reals.
real, dimension(4) :: arrayb ! another way to declare an array. real :: array(6)
integer :: arrayc(-10:10) ! an array with a custom index. ! another way to declare an array.
real :: array2d(3, 2) ! multidimensional array. real, dimension(4) :: arrayb
! an array with a custom index -10 to 10 (inclusive)
integer :: arrayc(-10:10)
! A multidimensional array.
real :: array2d(3, 2)
! The '::' separators are not always necessary but are recommended. ! The '::' separators are not always necessary but are recommended.
@ -76,8 +81,8 @@ program example ! declare a program called example.
! Assignment & Arithmetic ! Assignment & Arithmetic
! ======================= ! =======================
Z = 1 ! assign to variable z declared above (case insensitive). Z = 1 ! assign to variable z declared above
j = 10 + 2 - 3 j = 10 + 2 - 3
a = 11.54/(2.3*3.1) a = 11.54/(2.3*3.1)
b = 2**3 ! exponentiation b = 2**3 ! exponentiation
@ -86,7 +91,7 @@ program example ! declare a program called example.
! =================================== ! ===================================
! Single-line if statement ! Single-line if statement
if (z == a) b = 4 ! condition always need surrounding parentheses. if (z == a) b = 4 ! conditions always need parentheses.
if (z /= a) then ! z not equal to a if (z /= a) then ! z not equal to a
! Other symbolic comparisons are < > <= >= == /= ! Other symbolic comparisons are < > <= >= == /=
@ -98,13 +103,13 @@ program example ! declare a program called example.
b = 5 ! execution block must be on a new line. b = 5 ! execution block must be on a new line.
else else
b = 10 b = 10
end if ! end statement needs the 'if' (or can use 'endif'). end if ! end statement needs the 'if'
if (.NOT. (x < c .AND. v >= a .OR. z == z)) then ! boolean operators. if (.NOT. (x < c .AND. v >= a .OR. z == z)) then ! boolean operators.
inner: if (.TRUE.) then ! can name if-construct. inner: if (.TRUE.) then ! can name if-construct.
b = 1 b = 1
end if inner ! then must name endif statement. end if inner ! then must name endif statement.
end if endif ! 'endif' is equivalent to 'end if'
i = 20 i = 20
select case (i) select case (i)
@ -128,16 +133,16 @@ program example ! declare a program called example.
j = -1 j = -1
end select monthly end select monthly
do i = 2, 10, 2 ! loops from 2 to 10 (inclusive) in increments of 2. do i = 2, 10, 2 ! loops from 2 to 10 (inclusive) in steps of 2.
innerloop: do j = 1, 3 ! loops can be named too. innerloop: do j = 1, 3 ! loops can be named too.
exit ! quits the loop. exit ! quits the loop.
end do innerloop end do innerloop
cycle ! jump to next loop iteration. cycle ! jump to next loop iteration.
end do end do
! Goto statement exists but it is heavily discouraged though. ! Goto statement exists but it is heavily discouraged.
goto 10 goto 10
stop 1 ! stops code immediately (returning specified condition code). stop 1 ! stops the program, returns condition code 1.
10 j = 201 ! this line is labeled as line 10 10 j = 201 ! this line is labeled as line 10
! Arrays ! Arrays
@ -209,8 +214,12 @@ program example ! declare a program called example.
! we can have multiple format specifications. ! we can have multiple format specifications.
print "(I5,F6.2,E6.2)", 120, 43.41, 43.41 print "(I5,F6.2,E6.2)", 120, 43.41, 43.41
print "(3I5)", 10, 20, 30 ! 3 repeats of integers (field width = 5).
print "(2(I5,F6.2))", 120, 43.42, 340, 65.3 ! repeated grouping of formats. ! 3 repeats of integers (field width = 5).
print "(3I5)", 10, 20, 30
! repeated grouping of formats.
print "(2(I5,F6.2))", 120, 43.42, 340, 65.3
! We can also read input from the terminal. ! We can also read input from the terminal.
read (*, *) v read (*, *) v
@ -225,8 +234,9 @@ program example ! declare a program called example.
! To read a file. ! To read a file.
open (newunit=m, file="records.txt", status="old") open (newunit=m, file="records.txt", status="old")
! The file is referred to by a 'new unit number', an integer that the compiler ! The file is referred to by a 'new unit number',
! picks for you. ! an integer that the compiler picks for you.
read (unit=m, fmt="(3F10.2)") a, b, c read (unit=m, fmt="(3F10.2)") a, b, c
close (m) close (m)
@ -241,7 +251,7 @@ program example ! declare a program called example.
call cpu_time(v) ! sets 'v' to a time in seconds. call cpu_time(v) ! sets 'v' to a time in seconds.
k = ior(i, j) ! bitwise OR of 2 integers. k = ior(i, j) ! bitwise OR of 2 integers.
v = log10(x) ! log base 10. v = log10(x) ! log base 10.
i = floor(b) ! returns the closest integer less than or equal to x. i = floor(b) ! converts b to integer by rounding down.
v = aimag(w) ! imaginary part of a complex number. v = aimag(w) ! imaginary part of a complex number.
! Functions & Subroutines ! Functions & Subroutines
@ -252,7 +262,7 @@ program example ! declare a program called example.
call routine(a, c, v) ! subroutine call. call routine(a, c, v) ! subroutine call.
! A function takes a list of input parameters and returns a single value. ! A function takes several input parameters and returns a single value.
! However the input parameters may still be modified and side effects ! However the input parameters may still be modified and side effects
! executed. ! executed.
@ -261,21 +271,22 @@ program example ! declare a program called example.
! Function calls can also be evoked within expressions. ! Function calls can also be evoked within expressions.
print *, func2(3, 2, k) print *, func2(3, 2, k)
! A pure function is a function that doesn't modify its input parameters ! A pure function is a function that doesn't modify its input
! or cause any side-effects. ! parameters or cause any side-effects.
m = func3(3, 2, k) m = func3(3, 2, k)
contains ! Zone for defining sub-programs internal to the program. contains ! Start defining the program's internal procedures:
! Fortran has a couple of slightly different ways to define functions. ! Fortran has a couple of slightly different ways to define functions.
integer function func(a, b, c) ! a function returning an integer value. integer function func(a, b, c) ! a function returning an integer value.
! implicit none ! subvariable fields can no longer declare implicit none ! implicit none ! - no longer used in subvariable fields
integer, intent(in) :: a, b, c ! type of input parameters defined inside the function. integer, intent(in) :: a, b, c ! type of input parameters
! the return variable defaults to the function name.
if (a >= 2) then if (a >= 2) then
func = a + b + c ! the return variable defaults to the function name. func = a + b + c
return ! can return the current value from the function at any time. return ! returns the current value at 'func'
end if end if
func = a + c func = a + c
@ -286,24 +297,29 @@ contains ! Zone for defining sub-programs internal to the pro
integer, intent(in) :: a, b ! can declare and enforce that variables integer, intent(in) :: a, b ! can declare and enforce that variables
!are not modified by the function. !are not modified by the function.
integer, intent(inout) :: c integer, intent(inout) :: c
integer :: f ! function return type declared inside the function. integer :: f
integer :: cnt = 0 ! GOTCHA - initialisation implies variable is ! function return type declared inside the function.
!saved between function calls. integer :: cnt = 0 ! GOTCHA -
! assigning a value at initalization
! implies that the variable is
! saved between function calls.
f = a + b - c f = a + b - c
c = 4 ! altering the value of an input variable. c = 4 ! changing value of input variable c.
cnt = cnt + 1 ! count number of function calls. cnt = cnt + 1 ! count number of function calls.
end function func2 end function func2
pure function func3(a, b, c) ! a pure function can have no side-effects. pure function func3(a, b, c) ! a pure function has no side-effects.
integer, intent(in) :: a, b, c integer, intent(in) :: a, b, c
integer :: func3 integer :: func3
func3 = a*b*c func3 = a*b*c
end function func3 end function func3
! a subroutine does not return anything,
! but can change the value of arguments.
subroutine routine(d, e, f) subroutine routine(d, e, f)
real, intent(inout) :: f real, intent(inout) :: f
real, intent(in) :: d, e real, intent(in) :: d, e
@ -312,7 +328,8 @@ contains ! Zone for defining sub-programs internal to the pro
end subroutine routine end subroutine routine
end program example ! End of Program Definition ----------------------- end program example
! End of Program Definition -----------------------
! Functions and Subroutines declared externally to the program listing need ! Functions and Subroutines declared externally to the program listing need
! to be declared to the program using an Interface declaration (even if they ! to be declared to the program using an Interface declaration (even if they
@ -350,7 +367,8 @@ module fruity
use fruit, only: apple, pear ! use apple and pear from fruit module. use fruit, only: apple, pear ! use apple and pear from fruit module.
implicit none ! comes after module imports. implicit none ! comes after module imports.
private ! make things private to the module (default is public). ! By default all module data and functions will be public
private ! Instead set default to private
! Declare some variables/functions explicitly public. ! Declare some variables/functions explicitly public.
public :: apple, mycar, create_mycar public :: apple, mycar, create_mycar
! Declare some variables/functions private to the module (redundant here). ! Declare some variables/functions private to the module (redundant here).

View File

@ -14,30 +14,90 @@ This document follows [TOML v1.0.0](https://toml.io/en/v1.0.0). Future [changes]
```toml ```toml
# Comments in TOML look like this. # Comments in TOML look like this.
################ ##################
# SCALAR TYPES # # Key/Value Pair #
################ ##################
# Our root object (which continues for the entire document) will be a map,
# which is equivalent to a dictionary, hash or object in other languages.
# The primary building block of a TOML document is the key/value pair.
# The key, equals sign, and value must be on the same line # The key, equals sign, and value must be on the same line
# (though some values can be broken over multiple lines). # (though some values can be broken over multiple lines).
key = "value" key = "value"
# Valus types must be one of the followings.
string = "hello" string = "hello"
number = 42 integer = 42
float = 3.14 float = 3.14
boolean = true boolean = true
dateTime = 1979-05-27T07:32:00-08:00 offsetDateTime = 1979-05-27T07:32:00Z
scientificNotation = 1e+12 localDateTime = 1979-05-27T07:32:00
"key can be quoted" = true # Both " and ' are fine localDate = 1979-05-27
"unquoted key may contain" = "letters, numbers, underscores, and dashes" localTime = 07:32:00
other_kêys = "are permitted by spec but most implementations don't actually permit them" array = [ 1, 2, 3 ]
inlineTable = { first = "Tom", last = "Preston-Werner" }
# A key may be either bare, quoted, or dotted.
## bare
bare_key = "value" # bare keys may only contain ASCII letters/digits, underscore, and dashes
1234 = "value" # only-digits bare keys are allowed
= "no key name" # empty bare key is invalid
# defining duplicated key is invalid
name = "Tom"
name = "Pradyun" # invalid
## quoted
"key can be quoted" = true # Both " and ' are fine
# A bare key must be non-empty, but an empty quoted key is allowed # A bare key must be non-empty, but an empty quoted key is allowed
"" = "blank" # VALID but discouraged "" = "blank" # VALID but discouraged
'' = 'blank' # VALID but discouraged '' = 'blank' # VALID but discouraged
# between bare and quoted key, best practice is to use bare keys except when absolutely necessary
## dotted
# dotted keys are a sequence of bare or quoted keys joined with a dot.
# This allows for grouping similar properties together:
name = "Orange"
physical.color = "orange"
physical.shape = "round"
site."google.com" = true
# In JSON land, that would give you the following structure:
# {
# "name": "Orange",
# "physical": {
# "color": "orange",
# "shape": "round"
# },
# "site": {
# "google.com": true
# }
# }
# Tips: online TOML/JSON converter like this helps to understand TOML document structure
# https://pseitz.github.io/toml-to-json-online-converter/
other_kêys = "are permitted by spec but most implementations don't actually permit them"
## When defining long dotted key, indirectly defined key can be wrote into.
# Below indirectly makes the key "fruit" and "apple" into a table (more on table below).
fruit.apple.smooth = true
# So then you can add to the "fruit" and "apple" like so:
fruit.orange = 2
fruit.apple.amount = 1
# In JSON land, that would give you the following structure:
# {
# "fruit": {
# "orange": 2,
# "apple": {
# "amount": 1,
# "smooth": true
# }
# }
# }
# And obviously, you can not do this:
fruit.apple = "something" # because that would be a duplicated key for 'fruit.apple'
########## ##########
# String # # String #
########## ##########
@ -61,17 +121,19 @@ The first newline is trimmed in raw strings.
is preserved. #! are preserved? is preserved. #! are preserved?
''' '''
# For binary data it is recommended that you use Base64, another ASCII or UTF8 # Control characters other than tab are not permitted in a literal string.
# Thus, for binary data it is recommended that you use Base64, another ASCII or UTF8
# encoding. The handling of that encoding will be application specific. # encoding. The handling of that encoding will be application specific.
########### ###########
# Integer # # Integer #
########### ###########
## Integers can start with a +, a - or nothing. # Integers can start with a +, a - or nothing.
## Leading zeros are not allowed. # Leading zeros are not allowed.
## Hex, octal, and binary forms are allowed. # Hex, octal, and binary forms are allowed.
## Values that cannot be expressed as a series of digits are not allowed. # Values that cannot be expressed as a series of digits are not allowed.
int1 = +42 int1 = +42
int2 = 0 int2 = 0
int3 = -21 int3 = -21
@ -80,10 +142,12 @@ int5 = 0o755
int6 = 0b11011100 int6 = 0b11011100
integerRange = 64 integerRange = 64
## You can use underscores to enhance readability. Each # You can use underscores to enhance readability.
## underscore must be surrounded by at least one digit. # Each underscore must be surrounded by at least one digit on each side.
int4 = 5_349_221 int4 = 5_349_221
int5 = 1_2_3_4_5 # VALID but discouraged int5 = 1_2_3_4_5 # VALID but discouraged
int6 = _1_2_3 # INVALID
######### #########
# Float # # Float #
@ -94,6 +158,7 @@ flt1 = 3.1415
flt2 = -5e6 flt2 = -5e6
flt3 = 6.626E-34 flt3 = 6.626E-34
########### ###########
# Boolean # # Boolean #
########### ###########
@ -102,6 +167,7 @@ bool1 = true
bool2 = false bool2 = false
boolMustBeLowercase = true boolMustBeLowercase = true
############ ############
# Datetime # # Datetime #
############ ############
@ -111,6 +177,7 @@ date2 = 1979-05-26T15:32:00+08:00 # with RFC 3339/ISO 8601 offset
date3 = 1979-05-27T07:32:00 # without offset date3 = 1979-05-27T07:32:00 # without offset
date4 = 1979-05-27 # without offset or time date4 = 1979-05-27 # without offset or time
#################### ####################
# COLLECTION TYPES # # COLLECTION TYPES #
#################### ####################
@ -131,12 +198,13 @@ array5 = [
# Table # # Table #
######### #########
# Tables (or hash tables or dictionaries) are collections of key/value ## Tables (also known as hash tables or dictionaries) are collections of key/value pairs.
# pairs. They appear in square brackets on a line by themselves. # They are defined by headers, with square brackets on a line by themselves.
# Empty tables are allowed and simply have no key/value pairs within them. # Empty tables are allowed and simply have no key/value pairs within them.
[table] [table]
# Under that, and until the next table or EOF are the key/values of that table.
## Under that, and until the next table or EOF are the key/values of that table.
# Key/value pairs within tables are not guaranteed to be in any specific order. # Key/value pairs within tables are not guaranteed to be in any specific order.
[table-1] [table-1]
key1 = "some string" key1 = "some string"
@ -146,65 +214,107 @@ key2 = 123
key1 = "another string" key1 = "another string"
key2 = 456 key2 = 456
# Dots are prohibited in bare keys because dots are used to signify nested tables.
# Naming rules for each dot separated part are the same as for keys. ## Naming rules for tables are the same as for keys.
[dog."tater.man"] [dog."tater.man"]
type = "pug" type = "pug"
# In JSON land, that would give you the following structure: # In JSON land, that would give you the following structure:
# { "dog": { "tater.man": { "type": "pug" } } } # {
# "dog": {
# "tater.man": {
# "type": "pug"
# }
# }
# }
# Whitespace around dot-separated parts is ignored, however, best practice is to ## Whitespace around dot-separated parts is ignored, however, best practice is to
# not use any extraneous whitespace. # not use any extraneous whitespace.
[a.b.c] # this is best practice [a.b.c] # this is best practice
[ d.e.f ] # same as [d.e.f] [ d.e.f ] # same as [d.e.f]
[ j . "ʞ" . 'l' ] # same as [j."ʞ".'l'] [ j . "ʞ" . 'l' ] # same as [j."ʞ".'l']
# You don't need to specify all the super-tables if you don't want to. TOML knows
## You don't need to specify all the super-tables if you don't want to. TOML knows
# how to do it for you. # how to do it for you.
# [x] you # [x] you
# [x.y] don't # [x.y] don't
# [x.y.z] need these # [x.y.z] need these
[x.y.z.w] # for this to work [x.y.z.w] # for this to work
# As long as a super-table hasn't been directly defined and hasn't defined a
# specific key, you may still write to it.
[a.b]
c = 1
[a]
d = 2
# Will generate the following in JSON:
# { "a": {"b": {"c": 1}, "d": 2 } }
# You cannot define any key or table more than once. Doing so is invalid.
## Like keys, you cannot define a table more than once. Doing so is invalid.
# DO NOT DO THIS # DO NOT DO THIS
[a] [fruit]
b = 1 apple = "red"
[a] [fruit] # invalid: key duplication
c = 2 orange = "orange"
# DO NOT DO THIS EITHER # DO NOT DO THIS EITHER
[a] [fruit]
b = 1 apple = "red"
[a.b] [fruit.apple] # fruit.apple is a string, not a table, thus can not add key/value pair
c = 2 texture = "smooth"
# All table names must be non-empty.
## The whole TOML document is a top-level table, starts at the beginning of the
# document and ends just before the first table header (or EOF). Unlike other
# tables, it is nameless and cannot be relocated.
## Dotted keys create and define a table for each key part before the last one,
# provided that such tables were not previously created. Examples:
# This line also...
fruit.apple.color = "red"
# defines a table named fruit
# defines a table named fruit.apple
# Similarly, this line also...
fruit.apple.taste.sweet = true
# defines a table named fruit.apple.taste
# fruit and fruit.apple were already created
## Since tables cannot be defined more than once, redefining such tables using
# a [table] header is not allowed. Likewise, using dotted keys to redefine tables
# already defined in [table] form is not allowed.
[fruit]
apple.color = "red"
apple.taste.sweet = true
# table named fruit, fruit.apple, fruit.apple.taste defined
# so belows are invalid:
[fruit.apple] # INVALID
[fruit.apple.taste] # INVALID
# The [table] form can, however, be used to define sub-tables within tables defined via dotted keys.
[fruit]
apple.color = "red"
apple.taste.sweet = true
# same as above, fruit, fruit.apple, fruit.apple.taste defined
# below add sub-table named fruit.apple.texture
[fruit.apple.texture] # you can add sub-tables
smooth = true
## All table names must be non-empty.
[] # INVALID [] # INVALID
[a.] # INVALID [a.] # INVALID
[a..b] # INVALID [a..b] # INVALID
[.b] # INVALID [.b] # INVALID
[.] # INVALID [.] # INVALID
################ ################
# Inline table # # Inline table #
################ ################
# Inline tables provide a more compact syntax for expressing tables.
# They are intended to appear on a single line.
inlineTables = { areEnclosedWith = "{ and }", a = { b = { c = { d = 1 } } } } inlineTables = { areEnclosedWith = "{ and }", a = { b = { c = { d = 1 } } } }
point = { x = 1, y = 2 } point = { x = 1, y = 2 }
usingMultiple = { usingMultiple = {
@ -212,50 +322,55 @@ usingMultiple = {
instead = "use normal TOML tables", instead = "use normal TOML tables",
} }
# this inline table:
name = { first = "Tom", last = "Preston-Werner" }
# is equivalent to this standard table:
[name]
first = "Tom"
last = "Preston-Werner"
################### ###################
# Array of Tables # # Array of Tables #
################### ###################
# An array of tables can be expressed by using a table name in double brackets. ## An array of tables can be expressed by using a table name in double brackets.
# Each table with the same double bracketed name will be an item in the array. # Each table with the same double bracketed name will be an item in the array.
# The tables are inserted in the order encountered. # The tables are inserted in the order encountered.
[[products]] [[products]] # define array and first table element
name = "array of table" name = "array of table"
sku = 738594937 sku = 738594937
emptyTableAreAllowed = true emptyTableAreAllowed = true
[[products]] [[products]] # second element is an empty table
[[products]] [[products]] # third table element
name = "Nail" name = "Nail"
sku = 284758393 sku = 284758393
color = "gray" color = "gray"
```
The equivalent in JSON would be: # The equivalent in JSON would be:
# {
# "products": [
# {
# "name": "array of table",
# "sku": 7385594937,
# "emptyTableAreAllowed": true
# },
# {},
# {
# "name": "Nail",
# "sku": 284758393,
# "color": "gray"
# }
# ]
# }
```json
{
"products": [
{
"name": "array of table",
"sku": 7385594937,
"emptyTableAreAllowed": true
},
{},
{
"name": "Nail",
"sku": 284758393,
"color": "gray"
}
]
}
```
```toml ## You can create nested arrays of tables as well. Each double-bracketed
# You can create nested arrays of tables as well. Each double-bracketed
# sub-table will belong to the nearest table element above it. # sub-table will belong to the nearest table element above it.
#
[[fruit]] [[fruit]]
name = "apple" # I am a property in fruit table/map name = "apple" # I am a property in fruit table/map
@ -278,30 +393,59 @@ The equivalent in JSON would be:
[[fruit.color]] [[fruit.color]]
name = "yellow" name = "yellow"
note = "I am an array item in banana fruit's table/map" note = "I am an array item in banana fruit's table/map"
```
The equivalent in JSON would be: # According to spec, indentation is treated as whitespace and ignored.
# Here is just for better demonstration.
# The equivalent in JSON would be:
# {
# "fruit": [
# {
# "name": "apple",
# "geometry": { "shape": "round", "note": "..."},
# "color": [
# { "name": "red", "note": "..." },
# { "name": "green", "note": "..." }
# ]
# },
# {
# "name": "banana",
# "color": [
# { "name": "yellow", "note": "..." }
# ]
# }
# ]
# }
## The following TOML is invalid
# this table by itself is subtable, but what unclear is its parent element type
[fruit.physical]
color = "red"
shape = "round"
# and if this array of tables definition follows
# parser will complain the key fruit is already defined
[[fruit]]
name = "apple"
# But otherwise this TOML would be valid
# array of tables comes first
[[fruit]]
name = "apple"
# the following is array's first element
[fruit.physical]
color = "red"
shape = "round"
# As spec explained:
# If the parent of a table or array of tables is an array element, that element
# must already have been defined before the child can be defined.
# Use TOML/JSON Online converter to get the hang of it.
``` ```
{
"fruit": [
{
"name": "apple",
"geometry": { "shape": "round", "note": "..."},
"color": [
{ "name": "red", "note": "..." },
{ "name": "green", "note": "..." }
]
},
{
"name": "banana",
"color": [
{ "name": "yellow", "note": "..." }
]
}
]
}
```
### More Resources ### More Resources