Notifying when using high CPU. Via AppleScript or Automator? - macos

I'd like to automate that whenever a process is using more than 50% CPU
it sends a notification to my Notification Center
I'm using terminal-notifier for sending trough notifications
but I'm a bit stuck on what the best method is for creating this automation.
Should I use Automator.app or create a custom AppleScript and if so,
how do I make it to always be on?

If this is for interactive use, let me suggest a pragmatic alternative:
Run Activity Monitor.
Control-click its dock icon.
Select Dock Icon > Show CPU Usage - or, for a floating window, Monitors > Show CPU Usage.
You'll get a per-core display of current CPU usage - clicking on it will show the full Activity Monitor window, where you can sort by CPU usage.
If you do need an automated solution, I suggest:
writing a bash script that uses top to find the highest-CPU-percentage task and invokes terminal-notifier, if above the threshold.
scheduling that script as a launchd task for periodic invocation.
Automator and AppleScript are probably too heavy for such - presumably frequent - background activity.
Even running top itself uses quite a bit of CPU.
Here's a simple bash script that roughly does what you want:
#!/usr/bin/env bash
read pct name < <(top -l 2 -n 1 -F -o cpu -stats cpu,command | tail -1)
if (( ${pct%.*} >= 50 )); then
/Applications/terminal-notifier.app/Contents/MacOS/terminal-notifier \
-message "Process > 50%: $name ($pct%)"
fi
Note that this takes at least 2 seconds to run, because 2 samples (1 second apart) must be collected to calculate CPU-usage percentages, so consider that when determining how frequently to invoke the command.
Update - see below for step-by-step implementation instructions.
References:
As for scheduling the script to have launchd run it on login: see https://stackoverflow.com/a/22872222/45375
The general format of launchd *.plist files is described at https://developer.apple.com/library/mac/documentation/Darwin/Reference/Manpages/man5/launchd.plist.5.html or man launchd.plist; StartInterval is the key for specifying invocations every N seconds.
Step-by-step instructions for implementing the automated solution:
Create the bash script:
Create plain-text file ~/watchcpu (i.e., file watchcpu in your home folder), paste the above bash script into it, and save it.
Create the per-user launch agent for invocation at login and periodic invocation thereafter:
Create plain-text file ~/Library/LaunchAgents/WatchCPU.plist, paste the following XML document into it, and save it:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>KeepAlive</key>
<false/>
<key>Label</key>
<string>WatchCPU</string>
<key>ProgramArguments</key>
<array>
<string>bash</string>
<string>-c</string>
<string>. ~/watchcpu</string>
</array>
<key>RunAtLoad</key>
<true/>
<key>StartInterval</key>
<integer>15</integer>
</dict>
</plist>
Load the per-user launch agent to activate it:
Run the following command in Terminal (only needed once; from then on, the file will auto-load on every login):
launchctl load ~/Library/LaunchAgents/WatchCPU.plist
Note:
You're free to choose your own filenames and a different location for your bash script, but the launch agent .plist file MUST reside in ~/Library/LaunchAgents in order to be loaded automatically at login.
The interval (key StartInterval) is chosen at 15 seconds; again, you're free to change that, but note that choosing more frequent invocations doesn't make much sense, because launchd (the service that invokes launch agents) throttles agents whose execution time is too close to the invocation interval; I'm unclear on the details, but in the solution at hand an interval of 10 seconds results in frequent throttling notices in system.log (check via Console.app).

You can easily pull the CPU usage to use either with a script or in an Automator workflow. Here's a script that you can schedule to run on a schedule and will notify if usage is over 50%:
set theDelay to 3 -- number of seconds to sample the CPU
set CPUusage to do shell script "top -F -l " & theDelay & " -n 1 -stats cpu | grep 'CPU usage:' | tail -1 | cut -d. -f1"
set idlePercent to word -2 of CPUusage as number
if idlePercent < 50 then display notification ("CPU usage is at " & (100 - idlePercent) & "%.") with title "CPU Usage"
See the comments to follow the editing of the do shell script command to allow for getting the integer naturally from the shell command to work better with non-English systems.

Related

Detect Audio Output on Mac?

Is there a way to detect if audio is being output from the Mac system? Whether it's via headphone jack, usb-c, or bluetooth, is there a process which runs if and only if audio is playing?
I've made a unix script which plays a 15hz sine waveform, the idea is to execute the script every 580 seconds if and only if no audio is playing. If audio is playing, the script won't execute.
I have really good speakers but the drawback is they enter a 'standby' power saver mode every 10 minutes (600 seconds). When I'm at work I don't really care about whether it runs in the background or not* but when I'm at home I tend to miss notifications when speakers enter standby, so the aim of the script is to play the 3 second waveform every 580 seconds if and only if no audio is playing.
I'm not sure if this is super related to what you want but maybe try out Soundflower ? It's super useful for re-routing audio in mac.
You do not necessarily need to use AppleScript to accomplish the goal, although you certainly can if you want.
I'd opt to use a Launch Agent, as in the following example XML plist code:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>Label</key>
<string>com.my.play.if.no.audio.is.playing</string>
<key>ProgramArguments</key>
<array>
<string>/bin/bash</string>
<string>-c</string>
<string>[[ $(pmset -g | grep ' sleep') =~ coreaudiod ]] || '/path/to/shell_script'</string>
</array>
<key>RunAtLoad</key>
<false/>
<key>StartInterval</key>
<integer>580</integer>
</dict>
</plist>
Change '/path/to/shell_script' in the XML plist code to the actual fully qualified pathname of your shell script.
Then save is as, e.g., com.my.play.if.no.audio.is.playing.plist in ~/Library/LaunchAgents/ and load it from Terminal using, e.g.:
cd ~/Library/LaunchAgents/
launchctl load com.my.play.if.no.audio.is.playing.plist
Then every 580 seconds your shell script will execute if there is no audio playing.
Notes:
As coded, it assumes the executable bit is set on your shell script.
If you are going to use Launch Agents and Launch Daemons, I highly recommend you read the manual pages for launchctl, launchd.plist and launchd.
You can read the manual page for command in Terminal by typing man command, then press enter, or for easier reading, just type command and then right-click on it and select: Open man Page
To stop your Launch Agent, in Terminal:
cd ~/Library/LaunchAgents/
launchctl unload com.my.play.if.no.audio.is.playing.plist
You could also instead, include the test condition in your shell script, e.g.:
#!/bin/bash
if [[ ! $(pmset -g | grep ' sleep') =~ coreaudiod ]]; then
# Code to generate your sine waveform goes here.
fi
Then, the command used in the example XML plist code would be:
<key>ProgramArguments</key>
<array>
<string>/path/to/shell_script</string>
</array>
If you really want to use AppleScript, and assuming a Stay Open application, then:
Example AppleScript code:
on run
-- # Add any AppleScript code you what run when the
-- # Stay Open AppleScript application is opened.
end run
on idle
do shell script ¬
"[[ $(pmset -g | grep ' sleep') =~ coreaudiod ]] || '/path/to/shell_script'"
return 580
end idle
on quit
continue quit
end quit
Notes:
When saving the example AppleScript code in Script Editor , set File Format: [Application] and [√] Stay open after run handler.
If your add the test condition to your shell script, as shown further above, then your do shell script command would be:
do shell script "'/path/to/shell_script'"
I tend to stay away from using this type of AppleScript application, as I find that over time they can/may become resource intensive in that they continue consume more RAM. YMMV.

"Absurd Length" error in Automator Run Shell Script

So, I have this camera system which automatically uploads Videos to an FTP server when it detects motion.
Those files, I want to move to another FTP server automatically, (my Home Assistant server), which then pings my phone with a notification.
To Download and Upload between the two FTP servers, I'm using a tool called FavoriteFTP for Mac OS X. It allows me to set up profiles which you can run through a command line.
I then sat up 2 "Apps" through Automator to launch the different Profiles in Favorite FTP. One for Downloading all files from the remote FTP server and one for Uploading those files to another FTP (My Home Assistant Server).
Last but not least, I made a third Automator App, to transcode the files from AVI to MP4 using HandbrakeCLI.
So here are the 3 Automator Apps:
This is the ftpdownload app:
/Applications/FavoriteFTP.app/Contents/MacOS/FavoriteFTPPro -profile "Download from FTP"
This is the ftptranscode app:
SRC="/Users/frederik/cctv/motion"
DEST="/Users/frederik/cctv/motion"
DEST_EXT=mp4
HANDBRAKE_CLI=HandBrakeCLI
for FILE in "$SRC"/.avi
do
filename=$(basename "$FILE")
extension=${filename##.}
filename=${filename%.}
/usr/local/bin/HandBrakeCLI -i "$FILE" -o "$DEST"/"$filename".$DEST_EXT
done
find /Users/frederik/cctv/motion -name '.avi' -exec rm -r {} ;
And this is the ftpsync app (upload to second FTP):
/Applications/FavoriteFTP.app/Contents/MacOS/FavoriteFTPPro -profile "Upload CH1 to HASS
What my AppleScript then does, is running these 3 Apps in an infinite loop
on idle
tell application "System Events"
tell application "ftpdownload"
run
delay 10
end tell
tell application "ftptranscode"
run
delay 20
end tell
tell application "ftpsyncapp"
run
end tell
tell application "ftpsyncappCH2"
run
end tell
return 10
end tell
end idle
So to summarize:
ftpdownload is the app which downloads all AVI files from the remote FTP server
ftptranscode is the app which converts those files into MP4
ftpsyncapp is the app which then uploads those files to the second FTP server
and ftpsyncappCH2 does the same, but only with files with the word "CH2" in the filenames
Here's the problem
After a day or two, I get an error from one of the Automator Scripts (see image below). However I just get a single Window Popup. So Im thinking it's just one of the 3 automator Apps.
https://i.imgur.com/bmz7Xxv.png
It seems that there's a limit on how many times I can loop this
(I just need this running forever)
So right now, I have to click "OK" every day, which is a bit annoying.
How do I avoid getting this error message once a day, so my scripts can run in a loop forever?
I'm going to offer two suggestions.
First: Instead of using automator, create a stay-open script application that uses the do shell script function of AppleScript to do the work. The idle handler for that would look something like this:
on idle
do shell script "/Applications/FavoriteFTP.app/Contents/MacOS/FavoriteFTPPro -profile 'Download from FTP'"
do shell script "
SRC='/Users/frederik/cctv/motion'
DEST='/Users/frederik/cctv/motion'
DEST_EXT=mp4
HANDBRAKE_CLI=HandBrakeCLI
for FILE in \"$SRC\"/.avi
do
filename=$(basename \"$FILE\")
extension=${filename##.}
filename=${filename%.}
/usr/local/bin/HandBrakeCLI -i \"$FILE\" -o \"$DEST\"/\"$filename\".$DEST_EXT
done
find /Users/frederik/cctv/motion -name '.avi' -exec rm -r {} ;"
do shell script "/Applications/FavoriteFTP.app/Contents/MacOS/FavoriteFTPPro -profile 'Upload CH1 to HASS'"
do shell script "/Applications/FavoriteFTP.app/Contents/MacOS/FavoriteFTPPro -profile 'Upload CH2 to HASS'"
-- check every 30 seconds
return 30
end idle
Note that do shell script will in most cases wait for a response from the called script before advancing to the next applescript command, so the delay commands wouldn't be necessary. If the Favorite FTP is running its commands on detached background threads that might cause issues, but that seems unlikely.
Also, I used a 30 second idle period because I didn't want to re-invoke the FavoriteFTP app too often. By default, script apps have a one second idle interval; returning 30 makes that a 30 second interval, which ought to be enough for the app to finish its last cycle.
Second, since this is really just a set of shell scripts, and you're only using AppleScript as a container to run them periodically, you could just write the whole thing as a single shell script:
/Applications/FavoriteFTP.app/Contents/MacOS/FavoriteFTPPro -profile 'Download from FTP'
SRC='/Users/frederik/cctv/motion'
DEST='/Users/frederik/cctv/motion'
DEST_EXT=mp4
HANDBRAKE_CLI=HandBrakeCLI
for FILE in \"$SRC\"/.avi
do
filename=$(basename \"$FILE\")
extension=${filename##.}
filename=${filename%.}
/usr/local/bin/HandBrakeCLI -i \"$FILE\" -o \"$DEST\"/\"$filename\".$DEST_EXT
done
find /Users/frederik/cctv/motion -name '.avi' -exec rm -r {} ;
/Applications/FavoriteFTP.app/Contents/MacOS/FavoriteFTPPro -profile 'Upload CH1 to HASS'
/Applications/FavoriteFTP.app/Contents/MacOS/FavoriteFTPPro -profile 'Upload CH2 to HASS'
save it to disk, and run it on schedule as a launchd job. Launchd is designed to do that. You'll write a plist file that looks something like this:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>Label</key>
<string>user.ftp.transfer.mdvideos</string>
<key>Program</key>
<string>/path/to/shellscript</string>
<key>StartInterval</key>
<integer>30</integer>
</dict>
</plist>
save it at ~/Library/LaunchAgents/user.ftp.transfer.mdvideos.plist, then load it as a job using the unix command
launchctl load ~/Library/LaunchAgents/user.ftp.transfer.mdvideos.plist`
See man launchctl and man launchd.plist for details

Getting Launchd to repeatedly run a script without waiting for previous launch to finish in OSX

Let's say I have the script below
#! /bin/bash
sleep 300
dt=$(date '+%Y/%m/%d %H:%M:%S')
echo $dt >> /foo/bar/test.txt
When I set up a launchagent to trigger this script every 2 minutes... launchd will wait for the script to finish before triggering it again. So instead of the date every 2 minutes (after a 300 second sleep) I get it every 5 minutes or more. Is there a way for launchd to launch the script every 2 minutes, regardless of whether it has completed or not?
I haven't tested this, but you should be able to have the launch agent run the script in the background, something like this:
<key>ProgramArguments</key>
<array>
<string>/bin/bash</string>
<string>-c</string>
<string>/path/to/script &</string>
</array>
<key>AbandonProcessGroup</key>
<true/>
Notes: If you need to pass any arguments to your script, include them in the same <string> as the script path, delimited by spaces (rather than as separate <string>s, like you normally would in the launch daemon file). The AbandonProcessGroup key is needed to prevent launchd from "helpfully" killing any leftover subprocesses (like your actual script) when what it thinks of as the daemon process exits.

Script to detect if NAS is connected and if so mount Shares

I'm trying to find a way of mounting Shares (afp) on my NAS automatically. I use logins on it to control which shares are accessible by the computer (for privacy and other reasons). When switching logins not all of the shares get re-mounted which causes problems for some of the applications I run.
What I want to do is have a script which would run every time I login to the NAS (even if it's just guest login) then this script would mount the shares.
I was wondering if anyone could point me in the right direction. This is on an OS X computer so was thinking of using applescript to achieve this.
Thanks in advance
Tom
I have been fighting this problem on my mac for ages and believe i finally have a solution.
I have split it into two scripts:
the first one (exported in applescript editor as stay open application) runs on idle (rather than a repeat loop) and calls a second script every 10 seconds that handles the drive mounting. the errors that i check for in the first script are quite important as -128 ensures you can still quit the stay open script with right click or on osx shutdown, while the -5014 is an unknown error that unless explicitly handled pops up a dialog in my case.
--------------------------------------------------------------------------------------
--"On Idle Launch Basic Drive Mounter.app"
on idle
try
--script loads on startup, so first we wait 5 seconds to ensure network
delay 5
--run the mounter script which is on the desktop
run script file ":Users:localusername:Desktop:Basic Drive Mounter.app"
on error errStr number errorNumber
--listen for the apple quit command and quit
if the errorNumber is equal to -128 then
quit
return 1
--listen for the unknown error and ignore it
else if the errorNumber is equal to -5014 then
return 5
else
--all other errors are also ignored
return 5
end if
end try
--return with a wait of 5 seconds before next idle run
return 5
end idle
--------------------------------------------------------------------------------------
the second script (export as an application) does the checking of the network, then tries to mount the volume using a shell mount. i originally used a finder "mount volume" and that code exists as inline comments, but I didn't like the dialog popping up on errors; even if only for a second, so i moved on to shell script.
--------------------------------------------------------------------------------------
--"Basic Drive Mounter.app"
try
set IP_address to "xxx.xxx.xxx.xxx"
set IP_Valid to true
try
do shell script ("ping -c 2 " & IP_address)
on error
set IP_Valid to false
end try
if IP_Valid then
tell application "Finder"
if disk "work" exists then
else
try
do shell script "mkdir /Volumes/work"
end try
do shell script "mount_afp afp://xxx.xxx.xxx.xxx/work /Volumes/work/"
-->>finder mount volume version
--with timeout of 1 second
-- mount volume "afp://xxx.xxx.xxx.xxx/work"
--end timeout
--<<finder mount volume version
end if
end tell
end if
on error
return 0
-->>finder mount volume version
--on error finder returns an error dialog which needs to be closed to go back and retry
--tell application "System Events"
-- keystroke return
--end tell
--<<finder mount volume version
end try
--------------------------------------------------------------------------------------
once you have it working, drag the first script/app into your users login items, to have it automatically started when you log in. if you don't need the persistent remapping, then drag the second script/app into the login items for a single run.
The basic idea would be to make a launchd agent to watch a folder for changes. You will want to watch the /Volumes folder because when you login to your NAS something will get mounted in the Volumes folder. Thus the watch agent will detect that something changed in the Volumes folder and it will run a script.
It's very simple. You can google about launchd and find many examples. But to setup a watch folder use something like this...
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>WatchPaths</key>
<array>
<string>/Volumes</string>
</array>
<key>ProgramArguments</key>
<array>
<string>/usr/bin/osascript</string>
<string>/path/to/applescript</string>
</array>
<key>Label</key>
<string>com.someName.plistFileName</string>
</dict>
</plist>
So just create a text file with the above code. Save it with an extension of ".plist". Insert a path to the applescript in the ProgramArguments section and give it a name in the Label section.
Put this plist in ~/Library/LaunchAgents folder and restart your computer. Now every time something changes in the /Volumes folder the applescript will be run.
Then you just create the applescript properly. You will first need to check the Volumes folder and see if your NAS is mounted. If it is then mount any additional shares you want and if not then do nothing. You can google (or search stack overflow) how to mount shares using applescript.
Good luck.

Run a script only at shutdown (not log off or restart) on Mac OS X

Is there any way to run a script only at shutdown?
I mean, only when the computer is really shutting down to off state. This script should not run when doing just a log off or restart.
Few days ago I published on github a configuration/script able to be executed at boot/shutdown.
Basically on Mac OS X you could/should use a System wide and per-user daemon/agent configuration file (plist) in conjunction with a bash script file. This is a sample of the plist file you could use:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>Label</key><string>boot.shutdown.script.name</string>
<key>ProgramArguments</key>
<array>
<string>SCRIPT_PATH/boot-shutdown.sh</string>
</array>
<key>RunAtLoad</key>
<true/>
<key>StandardOutPath</key>
<string>LOG_PATH/boot-shutdown.log</string>
<key>StandardErrorPath</key>
<string>LOG_PATH/boot-shutdown.err</string>
</dict>
</plist>
You can place this file into /Library/LaunchDaemons. There are many directories where the plist file could be placed, it depends from what you need, the rights of the process and so on.
~/Library/LaunchAgents Per-user agents provided by the user.
/Library/LaunchAgents Per-user agents provided by the administrator.
/Library/LaunchDaemons System wide daemons provided by the administrator.
/System/Library/LaunchAgents Mac OS X Per-user agents.
/System/Library/LaunchDaemons Mac OS X System wide daemons.
This script boot-shutdown.sh will be loaded and executed at every boot/shutdown.
#!/bin/bash
function shutdown()
{
# INSERT HERE THE COMMAND YOU WANT EXECUTE AT SHUTDOWN OR SERVICE UNLOAD
exit 0
}
function startup()
{
# INSERT HERE THE COMMAND YOU WANT EXECUTE AT STARTUP OR SERVICE LOAD
tail -f /dev/null &
wait $!
}
trap shutdown SIGTERM
trap shutdown SIGKILL
startup;
Then call launchctl command which load and unload daemons/agents.
sudo launchctl load -w /Library/LaunchDaemons/boot-shutdown-script.plist
It looks like the most straightforward way would be to write a small C++ application that would run as a daemon with launchctl, catch the shutdown notification but ignore the reboot notification (see below) and then call whatever is given to it as arguments, e.g. a shell script. It does not look like Apple provides libraries to catch those notifications in any other language.
From the "Kernel Programming" manual https://developer.apple.com/library/mac/documentation/Darwin/Conceptual/KernelProgramming/KernelProgramming.pdf from Apple, page 150:
"Although OS X does not have traditional BSD-style shutdown hooks, the I/O Kit provides equivalent functionality in recent versions. Since the I/O Kit provides this functionality, you must call it from C++ code."
"To register for notification, you call registerSleepWakeInterest (described in IOKit/RootDomain.h) and register for sleep notification. If the system is about to be shut down, your handler is called with the message type kIOMessageSystemWillPowerOff. If the system is about to reboot, your handler gets the message type kIOMessageSystemWillRestart. If the system is about to reboot, your handler gets the message type kIOMessageSystemWillSleep."
As you can see there is a different message for reboot, so you can handle the shutdown case exclusively.
Here is a way that does work (I just tested it) but it is quite technical and not for inexperienced people... I put a wrapper around /sbin/shutdown. This will work even if you shutdown your Mac from the Apple menu in the GUI.
Basically, you need to su to root, like this, and rename the existing, Apple-supplied shutdown binary to shutdown.orig.
su -
cd /sbin
mv shutdown shutdown.orig
Then you create a bash script called shutdown that does what you want first, then execs the original Apple-supplied shutdown binary.
#!/bin/bash
Do something you want done before shutdown
exec /sbin/shutdown.orig "$#"
There are three things to watch out for...
1. Make all the permissions the same on shutdown as shutdown.orig
2. Parse the parameters to the originl shutdown and see if `-r` is one of them as this means it is a `restart` shutdown. You will also have to pass through the other parameters that Apple calls the script with - if any.
3. Apple may feel at liberty to overwrite your lovely, shiny, new `shutdown` script when updating OSX, so maybe abstract out the bulk of your personal shutdown script into another place so that you can easily re-insert a single-line call to it if/when Apple overwrites it at some point.
Be careful! And make a backup first!
https://developer.apple.com/library/archive/documentation/MacOSX/Conceptual/BPSystemStartup/Chapters/CustomLogin.html#//apple_ref/doc/uid/10000172i-SW10-SW1
I tested it on my MacOs 12.5.1,It does work!
cat LogoutHook.sh
#!/bin/bash
export BLUEUTIL_ALLOW_ROOT=1
function shutdown()
{
echo `date` >> /Users/blanc/.LaunchShell/shutdown_date.log
echo `whoami` >> /Users/blanc/.LaunchShell/shutdown_date.log
/usr/local/bin/blueutil -p 0
sleep 1
#exit 0
}
shutdown;
sudo defaults write com.apple.loginwindow LogoutHook /Users/blanc/.LaunchShell/LogoutHook.sh
In case someone comes to this answer like me googling for similar but somewhat different problem.
Due to CopyQ crash bug that I found https://github.com/hluk/CopyQ/issues/1301
I had to write a cron script which will reload if it crashes.
But I did not want to reload copyq, if copyq exits during shutdown or restart
I ended up using
if ps aux | grep "Finder.app" | grep -v grep
then
echo "I am still running"
else
echo "I am in shutdown"
fi
To detect if system is in shutdown, (you can use Chrome.app or any other always running app depending on your need)
not exactly the solution, but helped me solve a similar problem that I was having

Resources