how to bind JFX ProgressBar with my link in java - java

I am trying to make a java program download an app from my server by getting download link from it with this code :
private void downloadFile(String link) throws Exception {
URL url = new URL(link);
URLConnection conn = url.openConnection();
InputStream is = conn.getInputStream();
int max = conn.getContentLength();
pane.setText(pane.getText()+"\n"+"Downloding files...\nUpdate Size : "+(max/1000000)+" Mb");
BufferedOutputStream fOut = new BufferedOutputStream(new FileOutputStream(new
File("update.zip")));
byte[] buffer = new byte[32 * 1024];
int bytesRead = 0;
int in = 0;
while ((bytesRead = is.read(buffer)) != -1) {
in += bytesRead;
fOut.write(buffer, 0, bytesRead);
}
fOut.flush();
fOut.close();
is.close();
pane.setText(pane.getText()+"\nDownload Completed Successfully!");
and it is working fine ... I did search about how to bind my progress bar to this download link but I couldnt figure it out .... I would appreciate any kind of help.

Create a Task and perform your download in that Task’s call method:
String link = /* ... */;
File downloadsDir = new File(System.getProperty("user.home"), "Downloads");
downloadsDir.mkdir();
File file = File(downloadsDir, "update.zip");
Task<Void> downloader = new Task<Void>() {
#Override
public Void call()
throws IOException {
URL url = new URL(link);
URLConnection conn = url.openConnection();
long max = conn.getContentLengthLong();
updateMessage(
"Downloading files...\nUpdate Size : " + (max/1000000) + " MB");
try (InputStream is = conn.getInputStream();
BufferedOutputStream fOut = new BufferedOutputStream(
new FileOutputStream(file))) {
byte[] buffer = new byte[32 * 1024];
int bytesRead = 0;
long in = 0;
while ((bytesRead = is.read(buffer)) != -1) {
in += bytesRead;
fOut.write(buffer, 0, bytesRead);
updateProgress(in, max);
}
}
updateMessage("Download Completed Successfully!");
return null;
}
};
Notice the use of the inherited methods updateProgress and updateMessage.
Then you can simply bind the ProgressBar’s properties to your Task’s properties.
progressBar.progressProperty().bind(downloader.progressProperty());
And you can even monitor the Task’s message as it changes:
downloader.messageProperty().addListener(
(o, oldMessage, newMessage) -> pane.appendText("\n" + newMessage));
You’ll probably want to let the user know if the download fails. You can do this with the Task’s onFailed property:
downloader.setOnFailed(e -> {
Exception exception = downloader.getException();
StringWriter stackTrace = new StringWriter();
exception.printStackTrace(new PrintWriter(stackTrace));
TextArea stackTraceField = new TextArea(stackTrace.toString());
stackTraceField.setEditable(false);
Alert alert = new Alert(Alert.AlertType.ERROR);
alert.initOwner(pane.getScene().getWindow());
alert.setTitle("Download Failure");
alert.setHeaderText("Download Failed");
alert.setContextText(
"Failed to download " + link + ":\n\n" + exception);
alert.getDialogPane().setExpandableContent(stackTraceField);
alert.show();
});
Task implements Runnable, so you can start it by passing it to any standard multithreading class:
new Thread(downloader, "Downloading " + link).start();
Or:
CompletableFuture.runAsync(downloader);
Or:
ExecutorService executor = Executors.newCachedThreadPool();
executor.submit(downloader);

Related

Java URLConnection: How to detect file is complete on HTTP 416 Response?

I have the following dowload method that takes an URL and a File. It attempts to resume the file, but if the file is already completed it returns error 416 - Range Not Satisfiable.
How to detect the file is complete?
private void download(final URL source, final File file) throws IOException {
URLConnection connection = source.openConnection();
connection.setConnectTimeout(30);
connection.setReadTimeout(30);
FileOutputStream fos = null;
try {
if (file.exists()) {
fos = new FileOutputStream(file, true);
connection.setRequestProperty("Range", "bytes=" + file.length() + "-");
} else {
fos = new FileOutputStream(file);
}
try (InputStream in = connection.getInputStream()) {
try (BufferedOutputStream bout = new BufferedOutputStream(fos, 1024)) {
byte[] data = new byte[1024];
int x = 0;
while ((x = in.read(data, 0, 1024)) >= 0) {
bout.write(data, 0, x);
}
}
} catch (IOException ioe) {
if (connection instanceof HttpURLConnection) {
var httpUrlConn = (HttpURLConnection) connection;
int response = httpUrlConn.getResponseCode();
if (response == 416) {
}
}
}
} finally {
if (fos != null) {
fos.close();
}
}
}

PlayFramework. How to upload a photo using an external endpoint?

How do I upload a photo using a URL in the playframework?
I was thinking like this:
URL url = new URL("http://www.google.ru/intl/en_com/images/logo_plain.png");
BufferedImage img = ImageIO.read(url);
File newFile = new File("google.png");
ImageIO.write(img, "png", newFile);
But maybe there's another way. In the end I have to get the File and file name.
Example controller:
public static Result uploadPhoto(String urlPhoto){
Url url = new Url(urlPhoto); //doSomething
//get a picture and write to a temporary file
File tempPhoto = myUploadPhoto;
uploadFile(tempPhoto); // Here we make a copy of the file and save it to the file system.
return ok('something');
}
To get that photo you can use The play WS API, the code behind is an example extracted from the play docs in the section Processing large responses, I recommend you to read the full docs here
final Promise<File> filePromise = WS.url(url).get().map(
new Function<WSResponse, File>() {
public File apply(WSResponse response) throws Throwable {
InputStream inputStream = null;
OutputStream outputStream = null;
try {
inputStream = response.getBodyAsStream();
// write the inputStream to a File
final File file = new File("/tmp/response.txt");
outputStream = new FileOutputStream(file);
int read = 0;
byte[] buffer = new byte[1024];
while ((read = inputStream.read(buffer)) != -1) {
outputStream.write(buffer, 0, read);
}
return file;
} catch (IOException e) {
throw e;
} finally {
if (inputStream != null) {inputStream.close();}
if (outputStream != null) {outputStream.close();}
}
}
}
);
Where url is :
String url = "http://www.google.ru/intl/en_com/images/logo_plain.png"
This is as suggested in play documentation for large files:
*
When you are downloading a large file or document, WS allows you to
get the response body as an InputStream so you can process the data
without loading the entire content into memory at once.
*
Pretty much the same as the above answer then some...
Route: POST /testFile 'location of your controller goes here'
Request body content: {"url":"http://www.google.ru/intl/en_com/images/logo_plain.png"}
Controller(using code from JavaWS Processing large responses):
public static Promise<Result> saveFile() {
//you send the url in the request body in order to avoid complications with encoding
final JsonNode body = request().body().asJson();
// use new URL() to validate... not including it for brevity
final String url = body.get("url").asText();
//this one's copy/paste from Play Framework's docs
final Promise<File> filePromise = WS.url(url).get().map(response -> {
InputStream inputStream = null;
OutputStream outputStream = null;
try {
inputStream = response.getBodyAsStream();
final File file = new File("/temp/image");
outputStream = new FileOutputStream(file);
int read = 0;
byte[] buffer = new byte[1024];
while ((read = inputStream.read(buffer)) != -1) {
outputStream.write(buffer, 0, read);
}
return file;
} catch (IOException e) {
throw e;
} finally {
if (inputStream != null) {
inputStream.close();
}
if (outputStream != null) {
outputStream.close();
}
}
}); // copy/paste ended
return filePromise.map(file -> (Result) ok(file.getName() + " saved!")).recover(
t -> (Result) internalServerError("error -> " + t.getMessage()));
}
And that's it...
In order to serve the file after the upload phase you can use this answer(I swear I'm not promoting myself...): static asset serving from absolute path in play framework 2.3.x

Copy the dynamically incrementing log file data from FTP to local

I need to copy and paste dynamically incrementing log file data from FTP Server to local drive.
The below program I used can only do the copying one time. And not in the incremental manner.
public class ReadFtpFile {
public static void main(String[] args) throws UnknownHostException {
String server = "myIP";
int port = 20;
String user = "username";
String pass = "password";
FTPClient ftpClient = new FTPClient();
try {
ftpClient.connect(server, port);
ftpClient.login(user, pass);
ftpClient.enterLocalPassiveMode();
ftpClient.setFileType(FTP.BINARY_FILE_TYPE);
// APPROACH #2: using InputStream retrieveFileStream(String)
String remoteFile2 = "/folder/myfile.log";
File downloadFile2 = new File("F:/myfolder/mylogfile.log");
OutputStream outputStream2 = new BufferedOutputStream(new FileOutputStream(downloadFile2));
InputStream inputStream = ftpClient.retrieveFileStream(remoteFile2);
byte[] bytesArray = new byte[4096];
int bytesRead = -1;
while ((bytesRead = inputStream.read(bytesArray)) != -1) {
outputStream2.write(bytesArray, 0, bytesRead);
}
Boolean success = ftpClient.completePendingCommand();
if (success) {
System.out.println("File #2 has been downloaded successfully.");
}
outputStream2.close();
inputStream.close();
} catch (IOException ex) {
System.out.println("Error: " + ex.getMessage());
ex.printStackTrace();
} finally {
try {
if (ftpClient.isConnected()) {
ftpClient.logout();
ftpClient.disconnect();
}
} catch (IOException ex) {
ex.printStackTrace();
}
}
}
}
The log file data in the FTP server is growing for every second.I need to update the local file with new data in the FTP.
Replace the lines
OutputStream outputStream2 = new BufferedOutputStream(new FileOutputStream(downloadFile2));
InputStream inputStream = ftpClient.retrieveFileStream(remoteFile2);
with
ftpClient.setRestartOffset(downloadFile2.length());
InputStream inputStream = ftpClient.retrieveFileStream(remoteFile2);
OutputStream outputStream2 = new BufferedOutputStream(new FileOutputStream(downloadFile2, true));
This will check if the file already exists and, if so, download only the new data. If you need to do this periodically, add a loop around the whole try-catch block.
You need to update your code with Java threads and combine while loops to schedule this program for desired time.
String remoteFile2 = "/folder/myfile.log";
File downloadFile2 = new File("F:/myfolder/mylogfile.log");
OutputStream outputStream2 = new BufferedOutputStream(new FileOutputStream(downloadFile2));
InputStream inputStream = ftpClient.retrieveFileStream(remoteFile2);
byte[] bytesArray = new byte[4096];
int bytesRead = -1;
int minutecount=0;
while(minutecount==120){
while ((bytesRead = inputStream.read(bytesArray)) != -1) {
outputStream2.write(bytesArray, 0, bytesRead);
}
// Here i sceduled for every 1 minute
Thread.sleep(60*1000);
minutecount++;
}
Boolean success = ftpClient.completePendingCommand();
if (success) {
System.out.println("File #2 has been downloaded successfully.");
}
outputStream2.close();
inputStream.close();`

ANDROID - Send a screenshot from java to android via tcp socket

I made a Client-Server chat via sockets and it works great. Now I want to include an option for the server(Android phone) to grap a screenshot from the client(pc application). Creating the screenshot works fine, but the transfer from the client to the server fails every time.
CLIENT-SIDE / SENDER:
Before I wrote the image directly to an output stream, but I get an error on the server side and so I tried this way, but it's just the same.
public class ClientScreenshotThread implements Runnable {
// - Software Init - //
private Socket transferSocket;
private BufferedImage screenshot;
private Robot robot;
private BufferedWriter outToServer;
private FileInputStream inStream;
private DataOutputStream outStream;
// - Var Init - //
private final int SERVER_TRANSFER_PORT = 65000;
private int screenWidth, screenHeight;
// -------------------------------------------------- //
public ClientScreenshotThread() {
}
#Override
public void run() {
try {
SocketAddress sockaddr = new InetSocketAddress(Client.SERVER_IP, SERVER_TRANSFER_PORT);
transferSocket = new Socket();
transferSocket.connect(sockaddr, 5000); // 5sec Timeout
Dimension dimension = Toolkit.getDefaultToolkit().getScreenSize();
robot = new Robot();
screenWidth = dimension.width;
screenHeight = dimension.height;
Rectangle screen = new Rectangle(screenWidth, screenHeight);
screenshot = robot.createScreenCapture(screen);
ImageIO.write(screenshot, "png", new File("/Users/chris/Downloads/screenshot.png"));
File file = new File("/Users/chris/Downloads/screenshot.png");
inStream = new FileInputStream(file);
byte[] buffer = new byte[4096];
// prepare server for receiving the screenshot
outToServer = new BufferedWriter(new OutputStreamWriter(transferSocket.getOutputStream()));
outToServer.write("#!<cmd>screenshot");
outToServer.newLine();
outToServer.flush();
// send the screenshot to the server
outStream = new DataOutputStream(transferSocket.getOutputStream());
int n;
int i = 0;
while((n = inStream.read(buffer)) != -1) {
i++;
System.out.println(i + ". Byte[" + n + "]");
outStream.write(buffer, 0, n);
outStream.flush();
}
} catch(AWTException e1) {
System.out.println("AWT: " + e1.getMessage().toString());
} catch(IOException e2) {
System.out.println("IO: " + e2.getMessage().toString());
} finally {
try {
// close streams and socket
inStream.close();
outToServer.close();
transferSocket.close();
} catch(IOException e) {
System.out.println(e.getMessage().toString());
}
}
}
}
SERVER-SIDE / RECEIVER:
I always get a "NullPointerException" at:
bmp.compress(Bitmap.CompressFormat.PNG, 100, fileOutStream);
public class ServerTransferThread implements Runnable {
// - Software Init - //
private ServerSocket serverTransferSocket;
private Handler handler;
private BufferedReader inFromClient;
private DataInputStream inStream;
private ByteArrayOutputStream content;
private FileOutputStream fileOutStream;
// - Var Init - //
private final String TAG = "xxx";
private final int SERVER_TRANSFER_PORT = 65000;
// -------------------------------------------------- //
public ServerTransferThread(Handler _handler) {
this.handler = _handler;
}
#Override
public void run() {
Log.d(TAG, "ServerTransferThread: run()");
try {
serverTransferSocket = new ServerSocket(SERVER_TRANSFER_PORT);
while(ServerActivity.SERVER_STATE == true) {
Socket socket = serverTransferSocket.accept();
Log.d(TAG, "ServerTransferThread: accepted()");
inFromClient = new BufferedReader(new InputStreamReader(socket.getInputStream()));
Log.d(TAG, "ServerTransferThread: bufferedReader()");
String message = "";
if((message = inFromClient.readLine()) != null) {
if(message.equals("#!<cmd>screenshot")) {
receiveScreenshot(socket);
}
}
}
} catch(IOException e) {
Log.e(TAG, "ServerTransferThread 1: " + e.getMessage().toString());
} finally {
try {
inFromClient.close();
serverTransferSocket.close();
} catch (IOException e) {
Log.e(TAG, "ServerTransferThread 2: " + e.getMessage().toString());
}
}
}
private void receiveScreenshot(Socket socketX) {
Log.d(TAG, "ServerTransferThread: receiveScreenshot()");
try {
handler.sendMessage(buildMessage("> Receiving screenshot.."));
inStream = new DataInputStream(socketX.getInputStream());
byte[] buffer = new byte[4096];
content = new ByteArrayOutputStream();
inStream = new DataInputStream(socketX.getInputStream());
int n;
while((n = inStream.read()) != -1) {
content.write(buffer, 0, n); // HERE I "OUT OF MEMORY"
content.flush();
}
File directory = new File(ServerActivity.APP_FOLDER_PATH);
File screenshot = new File(ServerActivity.APP_FOLDER_PATH + "/" + "screenshot.png");
if(!directory.exists())
directory.mkdirs();
if(!screenshot.exists()) {
screenshot.createNewFile();
}
else {
screenshot.delete();
screenshot.createNewFile();
}
fileOutStream = new FileOutputStream(screenshot);
Bitmap bmp = BitmapFactory.decodeByteArray(content.toByteArray(), 0, content.size());
bmp.compress(Bitmap.CompressFormat.PNG, 100, fileOutStream);
handler.sendMessage(buildMessage("> Screenshot received sucessfully!"));
} catch(IOException e1) {
Log.e(TAG, "ServerTransferThread 3: " + e1.getMessage().toString());
} finally {
try {
inStream.close();
content.close();
fileOutStream.close();
socketX.close();
} catch (IOException e) {
Log.e(TAG, "ServerTransferThread 4: " + e.getMessage().toString());
}
}
}
private Message buildMessage(String text) {
Log.d(TAG, "ServerTransferThread: buildMessage()");
Message msg = handler.obtainMessage();
Bundle bundle = new Bundle();
bundle.putString("MESSAGE", text);
msg.setData(bundle);
return msg;
}
Here is my Logcat output:
08-20 19:01:18.285: D/skia(5383): --- SkImageDecoder::Factory returned null
08-20 19:01:18.295: W/dalvikvm(5383): threadid=12: thread exiting with uncaught exception (group=0x40c6b1f8)
08-20 19:01:18.295: E/AndroidRuntime(5383): FATAL EXCEPTION: Thread-3051
08-20 19:01:18.295: E/AndroidRuntime(5383): java.lang.NullPointerException
08-20 19:01:18.295: E/AndroidRuntime(5383): at net.api.speak.wifi.ServerTransferThread.receiveScreenshot(ServerTransferThread.java:114)
08-20 19:01:18.295: E/AndroidRuntime(5383): at net.api.speak.wifi.ServerTransferThread.run(ServerTransferThread.java:58)
08-20 19:01:18.295: E/AndroidRuntime(5383): at java.lang.Thread.run(Thread.java:856)
08-20 19:01:27.820: D/Speak WiFi(5383): Server: onDestroy()
08-20 19:01:27.830: E/Speak WiFi(5383): Server: Socket closed
08-20 19:01:27.830: E/Speak WiFi(5383): ServerThread: Socket closed
EDIT: After some troubles I've found a final solution for the file transfer problem! There it is:
Final Server side:
int bytecount = 2048;
byte[] buf = new byte[bytecount];
OutputStream OUT = socket.getOutputStream();
BufferedOutputStream BuffOUT = new BufferedOutputStream(OUT, bytecount);
FileInputStream in = new FileInputStream(itemPath);
int i = 0;
while ((i = in.read(buf, 0, bytecount)) != -1) {
BuffOUT.write(buf, 0, i);
BuffOUT.flush();
}
Final Client side:
FileOutputStream outToFile = new FileOutputStream(FileName);
int bytecount = 2048;
byte[] buf = new byte[bytecount];
// Create an inputstream for the file data to arrive
InputStream IN = socket.getInputStream();
BufferedInputStream BuffIN = new BufferedInputStream(IN, bytecount);
// Receiving file..
int i = 0;
int filelength = 0;
while((i = BuffIN.read(buf, 0, bytecount)) != -1) {
filelength += i;
outToFile.write(buf, 0, i);
outToFile.flush();
}
Could you write the received bytes directly to a FileOutputStream.
Converting the png to a bitmap on a rather limited device like a smartphone will cause problems sometimes.
Do you need to create the Bitmap object on the receiver side?
If not, you can do something like this:
InputStream is = socketX.getInputStream();
FileOutputStream outputFile = new FileOutputStream(screenshot);
int n;
while ((n = is.read(data, 0, data.length)) != -1) {
outputFile.write(data, 0, n);
}
I haven't tested the code.
The NullPointerException is because the BitmapFactory.decodeByteArray returns: The decoded bitmap, or null if the image could not be decode.
Server-side (inside receiveScreenshot() method), the part that writes the InputStream bytes into the ByteArrayOutputStream 'content' variable is not correct, because inStream.read() should be inStream.read(buffer)
The Out of Memory error can be explained because read() method only reads one byte at a time, and then for each byte you always write a full buffer of 4096 bytes.
Edit: To compress OutputStream to png once you have written all the bytes inside the fileOutputStream and when you don't want to directly provide the bytes (because in your case it is what didn't work):
// Write bytes inside fileOutStream
Bitmap bmp = BitmapFactory.decodeFile(screenshot.getAbsolutePath());
bmp.compress(Bitmap.CompressFormat.PNG, 100, fileOutStream);
fileOutStream.close();
This should work for your needs, but it's a pity to decode the file since you should already know the bytes inside..

URL - FileNotFoundException for image file in Android

I'm trying to get a image from particular URL but it throwsFileNotFoundException. If I try to open the url from my browser, i can see the images. Please help. Below is my code. Thanks.
String fileURL = "http://sposter.smartag.my/images/KFC_Voucher.jpg";
String FILENAME = "caldophilus.jpg";
URL u = new URL(fileURL);
HttpURLConnection c = (HttpURLConnection) u.openConnection();
c.setRequestMethod("GET");
c.setDoOutput(true);
c.connect();
File root = Environment.getExternalStorageDirectory();
FileOutputStream f = new FileOutputStream(new File(root, FILENAME));
InputStream x=c.getInputStream();
int size=x.available();
byte b[]= new byte[size];
x.read(b);
f.write(b);
f.flush();
f.close();
i try this and its work fine. Thanks.
URL url = new URL(fileURL);
URLConnection conexion = url.openConnection();
conexion.connect();
int lenghtOfFile = conexion.getContentLength();
Log.d("ANDRO_ASYNC", "Lenght of file: " + lenghtOfFile);
InputStream input = new BufferedInputStream(url.openStream());
OutputStream output = new FileOutputStream("/sdcard/caldophilus.jpg");
byte data[] = new byte[1024];
long total = 0;
while ((count = input.read(data)) != -1) {
total += count;
output.write(data, 0, count);
}
output.flush();
output.close();
input.close();
Try this:
BufferedInputStream inputStream = null;
OutputStream out = null;
String fileName = null;
String path = null;
File savedFile = null;
try
{
// Replace your URL here.
URL fileURL = new URL("http://enter.your.url.here");
URLConnection connection = fileURL.openConnection();
connection.connect();
inputStream = new java.io.BufferedInputStream(connection.getInputStream());
// Replace your save path here.
File fileDir = new File("path/to/save");
fileDir.mkdirs();
savedFile = new File("path/to/save", fileName);
out = new FileOutputStream(savedFile);
byte buf[] = new byte[1024];
int len;
long total = 0;
while ((len = inputStream.read(buf)) != -1)
{
total += len;
out.write(buf, 0, len);
}
out.close();
inputStream.close();
}
catch (Exception)
{
}
Try the below code. It should work!
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.URL;
public class DownloadManager {
public static void downLoadImage(String imageURL, String destinationFileName) throws IOException {
URL url = new URL(imageURL);
InputStream inputStream = url.openStream();
OutputStream outputStream = new FileOutputStream(destinationFileName);
byte[] byteData = new byte[2048];
int length;
while((length=inputStream.read(byteData))!=-1) {
outputStream.write(byteData, 0, length);
}
inputStream.close();
outputStream.close();
}
public static void main(String[] args) throws IOException {
String imageURL = "http://sposter.smartag.my/images/KFC_Voucher.jpg";
String destinationFileName = "C:/Users/sarath_sivan/Desktop/caldophilus.jpg";
downLoadImage(imageURL, destinationFileName);
}
}
Try this at once -
try {
url = paths[0];
HttpURLConnection connection = (HttpURLConnection) url
.openConnection();
int length = connection.getContentLength();
InputStream is = (InputStream) url.getContent();
byte[] imageData = new byte[length];
int buffersize = (int) Math.ceil(length / (double) 100);
int downloaded = 0;
int read;
while (downloaded < length) {
if (length < buffersize) {
read = is.read(imageData, downloaded, length);
} else if ((length - downloaded) <= buffersize) {
read = is.read(imageData, downloaded, length
- downloaded);
} else {
read = is.read(imageData, downloaded, buffersize);
}
downloaded += read;
publishProgress((downloaded * 100) / length);
}
Bitmap bitmap = BitmapFactory.decodeByteArray(imageData, 0,
length);
if (bitmap != null) {
Log.i(TAG, "Bitmap created");
} else {
Log.i(TAG, "Bitmap not created");
}
is.close();
return bitmap;
} catch (MalformedURLException e) {
Log.e(TAG, "Malformed exception: " + e.toString());
} catch (IOException e) {
Log.e(TAG, "IOException: " + e.toString());
} catch (Exception e) {
Log.e(TAG, "Exception: " + e.toString());
}
And, just take a look at here
In ...
FileOutputStream f = new FileOutputStream(new File(root, FILENAME));
Try replacing FILENAME with fileURL.
Also, at which line is the exception thrown? That would help.
String fileURL = "http://sposter.smartag.my/images/KFC_Voucher.jpg";
String FILENAME = "caldophilus.jpg";
URL u = new URL(fileURL);
HttpURLConnection c = (HttpURLConnection) u.openConnection();
c.setRequestMethod("GET");
//c.setDoOutput(true); =========== remove this;
c.connect();

Categories

Resources