c# How to write to a ini file [duplicate] - c#

This question already has answers here:
Reading/writing an INI file
(17 answers)
Closed 9 years ago.
I would like to know how i should write text to a ini file. The reading of the file is already done. Now i just have to know how to write to the file.
It should look like this when its in the INI file:
[H83052_md7]
Description=H83048 processor mode 7
BootFile=kernel_52.md7
Extension=a20
If you would like to see how i read from the file ask me for the source code please because i could not figure out how i should do this.
I write it like this:
namespace Flashloader
{
class Controllerlist : List<Controller>
{
public Controllerlist FromIniFile()
{
StringList input = new StringList().FromFile("Controllers.ini");
Controller controller = null;
foreach (var item in input)
{
String line = item.Trim();
if (line.StartsWith("[") && line.EndsWith("]"))
{
String name = line.Substring(1, line.Length - 2);
controller = new Controller(name);
Add(controller);
}
else if (controller != null)
{
int index = line.IndexOf('=');
if (index < 0)
continue;
String key = line.Substring(0, index).Trim();
String value = line.Substring(index + 1).Trim();
if (Utils.EqualsIgnoreCase(key, "Description"))
controller.Description = value;
else if (Utils.EqualsIgnoreCase(key, "Bootfile"))
controller.Bootfile = value;
else if (Utils.EqualsIgnoreCase(key, "Extension"))
controller.Extension = value;
}
}
return this;
}
public Controller FindByName(String name)
{
foreach (var item in this)
if (Utils.EqualsIgnoreCase(item.Name, name))
return item;
return null;
}
}
}

Try this class:
public class IniFile
{
public string path;
[DllImport("kernel32")]
private static extern long WritePrivateProfileString(string section,
string key,string val,string filePath);
[DllImport("kernel32")]
private static extern int GetPrivateProfileString(string section,
string key,string def, StringBuilder retVal,
int size,string filePath);
public IniFile(string INIPath)
{
path = INIPath;
}
public void IniWriteValue(string Section,string Key,string Value)
{
WritePrivateProfileString(Section,Key,Value,this.path);
}
public string IniReadValue(string Section,string Key)
{
StringBuilder temp = new StringBuilder(255);
int i = GetPrivateProfileString(Section,Key,"",temp,255, this.path);
return temp.ToString();
}
}

This is the best solution to write/read INi file. http://www.blackwasp.co.uk/IniFile.aspx

Related

How to shortcut a variable in C#?

I'm accessing a value object as follows: accounts[accountNum]
I want to do some minor manipulation on this object, ie: increase it by something, etc. Rather than typing "accounts[accountNum] += something" I'd rather do something like this:
MemberData account = accounts[accountNum];
account.balance += something;
Ie: "account" should be a direct pointer, reference, or somehow "be equivalent to" typing "accounts[accountNum]". But since this is a value type and not a reference type, it makes a copy and I cannot manipulate that object directly.
All my research on using "ref" seems to talk about using it within method parameters and return types, not in variables. Is there a simple way to shortcut a long variable name whilst still referencing the same object?
UPDATE:
Full source code - Please see specifically Line 46 & 51
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
/* * Description of the project:
* To implement an ATM machine which accepts deposits, withdrawals
* DEPOSIT / WITHDRAWAL:
* Account, Amount, Timestamp, TransactionID, Location
* Keep record of all accounts in TXT file, which is updated after each transaction. Of course in live system DB would be used.
* Keep another file that logs all transactions. Make it possible to LINQ the log associated with account, to show transaction history.
* TXT Accounts in form of:
* Account #, Name, Balance
* */
namespace ATMProject
{
class Program
{
static void Main(string[] args)
{
// Globals.DisplayAccounts();
// Deposit.MakeDeposit(1000009, 500, "sydney");
}
}
static class Deposit
{
//TODO Deposit: * Account #, Amount, Timestamp, TransactionID, Location
public static void MakeDeposit(long accountNum, long amount, string location)
{
string timestamp;
string transactionID;
timestamp = DateTime.Now.ToString("yyyyMMddhhmm");
transactionID = Globals.GenerateValidTransactionID();
using (StreamWriter sr = new StreamWriter(Globals.transactions, true))
{
string transactString = $"DEPOSIT| {accountNum}| {amount}| {timestamp}| {transactionID}| {location}";
sr.WriteLine(transactString);
}
Globals.WriteTransactionID(transactionID);
Dictionary<long, MemberData> accounts = Globals.GenerateAccounts();
try
{
//WORKS
MemberData account = accounts[accountNum];
account.balance += amount;
accounts[accountNum] = account;
//DOESN'T BUILD
//ref MemberData account = ref accounts[accountNum];
}
catch (KeyNotFoundException)
{
Console.WriteLine("Deposit failed, selected account number does not exist in accounts.txt");
}
}
}
static class Withdraw
{
}
static class CreateAccount
{
public static void Create(string name, long StartDeposit)
{
long accountNumber;
using (StreamReader sr = new StreamReader(Globals.accountIter))
{
accountNumber = Convert.ToInt64(sr.ReadLine());
sr.Close();
}
using (StreamWriter sr = new StreamWriter(Globals.accounts, true))
{
string accountAdd = $"{accountNumber}| {name}| {StartDeposit}";
sr.WriteLine(accountAdd);
Globals.SetNextAccountNumber();
Console.WriteLine("Successfully created account #" + accountNumber);
sr.Close();
}
}
}
struct MemberData
{
public long accountNum;
public string name;
public long balance;
public MemberData(long accountNum, string name, long balance)
{
this.accountNum = accountNum;
this.name = name;
this.balance = balance;
}
public override string ToString()
{
string thisStr = $"Account #: {accountNum}, Name: {name}, Balance: {balance}";
return thisStr;
}
}
static class Globals
{
public static string basepath = "C:\\Users\\root\\RiderProjects\\ConsoleApp1\\ATMProject\\";
public static string accounts = basepath + "accounts.txt"; //path to all accounts
public static string transactions = basepath + "transactions.txt"; //path to all accounts
public static string accountIter = basepath + "accountIter.txt"; //path to the current account iter
public static string transactIter = basepath + "transactIter.txt"; //path to the current account iter
//class values
public static long GetNextAccountNumber() //returns the next available account #
{
try
{
using (StreamReader sr = new StreamReader(accountIter))
{
long currAccountIter = Convert.ToInt64(sr.ReadLine());
sr.Close();
return currAccountIter;
}
}
catch (IOException e)
{
Console.WriteLine(e.Message);
return -1;
}
}
public static void SetNextAccountNumber() //increments the account #
{
long currAccountIter = GetNextAccountNumber();
if (currAccountIter == -1)
{
Console.WriteLine("Could not SetNextAccountNumber");
return;
}
using (StreamWriter sr = new StreamWriter(accountIter, false))
{
currAccountIter += 1;
sr.WriteLine(currAccountIter);
sr.Close();
}
}
public static Dictionary<long, MemberData> GenerateAccounts() //Returns Dictionary in form of <Account Number, MemberData>
{
Dictionary<long, MemberData> memberList = new Dictionary<long, MemberData>();
using (StreamReader sr = new StreamReader(accounts))
{
while (!sr.EndOfStream)
{
var memberSplit = sr.ReadLine().Split("| ", StringSplitOptions.RemoveEmptyEntries);
long accountNum = Convert.ToInt64(memberSplit[0]);
string name = memberSplit[1];
long balance = Convert.ToInt64(memberSplit[2]);
MemberData member = new MemberData(accountNum, name, balance);
memberList.Add(accountNum, member);
}
}
return memberList;
}
public static void DisplayAccounts()
{
Console.WriteLine("List of all Accounts:\n===========");
foreach (var member in GenerateAccounts())
{
Console.WriteLine(member.Value);
}
}
public static string GetTimestamp()
{
string timestamp = DateTime.Now.ToString("yyyyMMddhhmmss");
return timestamp;
}
private static string GetTransactionIter()
{
using (StreamReader sr = new StreamReader(transactIter))
{
string transactionID = sr.ReadLine();
sr.Close();
return transactionID;
}
}
public static string GenerateValidTransactionID()
{
string IDPart;
string timestamp = GetTimestamp();
string transactionID = GetTransactionIter();
string numberSlice = transactionID.Substring(14);
string timestampSlice = transactionID.Substring(0, 14);
if (timestamp == timestampSlice)
{
IDPart = Convert.ToString(Convert.ToInt64(numberSlice) + 1);
transactionID = timestamp + IDPart;
}
else
{
transactionID = timestamp + 0;
}
return transactionID;
}
public static void WriteTransactionID(string transactionID) //overwrite and write current transactionID to iter
{
using (StreamWriter sr = new StreamWriter(transactIter, false))
{
sr.WriteLine(transactionID);
sr.Close();
}
}
public static void GenereateAndWriteTransactionID()
{
WriteTransactionID(GenerateValidTransactionID());
}
}
}
Since C# 7 you can use local ref variables:
ref int niceName = ref localVariable.Values.SubArray.Here;
niceName += 20;
Note that you can not use this in async methods. And it does neither work with properties nor indexers (except for arrays).

Generate c# model class from csv file structure

The goal here is that after inputing csv file, a magic tool would output c# class with the fields from csv. Let's look at example.
Input myFile.csv:
Year,Make,Model
1997,Ford,E350
2000,Mercury,Cougar
Output myFile.cs
public class myFile
{
public string Year;
public string Make;
public string Model;
}
So, the only thing I would need to fix is the types of properties. After that I would use this class with FileHelpers to read csv file. Later it would be mapped to EntityFramework class (using AutoMapper) and saved to database.
Actually, https://csv2entity.codeplex.com/ looks like is doing what I need, but it just doesn't work - I installed it and nothing changed in my Visual studio, no new template appeared. The project is totally dead. Opened source code and ... decided maybe I'll just ask this question in stackoverflow :)
FileHelpers has only a simple wizard, which allows you to manually add fields. But I have 50 fields and this is not the last time I will need to do it, so automated solution is preferred here.
I believe this problem is solved many times before, any help?
Thank you Bedford, I took your code and added three things:
It removes symbols invalid for property names. For example "Order No." will become "OrderNo" property.
Ability to add property and class attributes. In my case I need [DelimitedRecord(",")] and [FieldOptional()], because I'm using FileHelpers.
Some columns don't have names, so it generates names itself. Naming convention is Column10, Column11 and so on.
Final code:
public class CsvToClass
{
public static string CSharpClassCodeFromCsvFile(string filePath, string delimiter = ",",
string classAttribute = "", string propertyAttribute = "")
{
if (string.IsNullOrWhiteSpace(propertyAttribute) == false)
propertyAttribute += "\n\t";
if (string.IsNullOrWhiteSpace(propertyAttribute) == false)
classAttribute += "\n";
string[] lines = File.ReadAllLines(filePath);
string[] columnNames = lines.First().Split(',').Select(str => str.Trim()).ToArray();
string[] data = lines.Skip(1).ToArray();
string className = Path.GetFileNameWithoutExtension(filePath);
// use StringBuilder for better performance
string code = String.Format("{0}public class {1} {{ \n", classAttribute, className);
for (int columnIndex = 0; columnIndex < columnNames.Length; columnIndex++)
{
var columnName = Regex.Replace(columnNames[columnIndex], #"[\s\.]", string.Empty, RegexOptions.IgnoreCase);
if (string.IsNullOrEmpty(columnName))
columnName = "Column" + (columnIndex + 1);
code += "\t" + GetVariableDeclaration(data, columnIndex, columnName, propertyAttribute) + "\n\n";
}
code += "}\n";
return code;
}
public static string GetVariableDeclaration(string[] data, int columnIndex, string columnName, string attribute = null)
{
string[] columnValues = data.Select(line => line.Split(',')[columnIndex].Trim()).ToArray();
string typeAsString;
if (AllDateTimeValues(columnValues))
{
typeAsString = "DateTime";
}
else if (AllIntValues(columnValues))
{
typeAsString = "int";
}
else if (AllDoubleValues(columnValues))
{
typeAsString = "double";
}
else
{
typeAsString = "string";
}
string declaration = String.Format("{0}public {1} {2} {{ get; set; }}", attribute, typeAsString, columnName);
return declaration;
}
public static bool AllDoubleValues(string[] values)
{
double d;
return values.All(val => double.TryParse(val, out d));
}
public static bool AllIntValues(string[] values)
{
int d;
return values.All(val => int.TryParse(val, out d));
}
public static bool AllDateTimeValues(string[] values)
{
DateTime d;
return values.All(val => DateTime.TryParse(val, out d));
}
// add other types if you need...
}
Usage example:
class Program
{
static void Main(string[] args)
{
var cSharpClass = CsvToClass.CSharpClassCodeFromCsvFile(#"YourFilePath.csv", ",", "[DelimitedRecord(\",\")]", "[FieldOptional()]");
File.WriteAllText(#"OutPutPath.cs", cSharpClass);
}
}
There is a link to full code and working example https://github.com/povilaspanavas/CsvToCSharpClass
You can generate the class code with a little C# app which checks all the values for each column. You can determine which is the narrowest type each one fits:
public static string CSharpClassCodeFromCsvFile(string filePath)
{
string[] lines = File.ReadAllLines(filePath);
string[] columnNames = lines.First().Split(',').Select(str => str.Trim()).ToArray();
string[] data = lines.Skip(1).ToArray();
string className = Path.GetFileNameWithoutExtension(filePath);
// use StringBuilder for better performance
string code = String.Format("public class {0} {{ \n", className);
for (int columnIndex = 0; columnIndex < columnNames.Length; columnIndex++)
{
code += "\t" + GetVariableDeclaration(data, columnIndex, columnNames[columnIndex]) + "\n";
}
code += "}\n";
return code;
}
public static string GetVariableDeclaration(string[] data, int columnIndex, string columnName)
{
string[] columnValues = data.Select(line => line.Split(',')[columnIndex].Trim()).ToArray();
string typeAsString;
if (AllDateTimeValues(columnValues))
{
typeAsString = "DateTime";
}
else if (AllIntValues(columnValues))
{
typeAsString = "int";
}
else if (AllDoubleValues(columnValues))
{
typeAsString = "double";
}
else
{
typeAsString = "string";
}
string declaration = String.Format("public {0} {1} {{ get; set; }}", typeAsString, columnName);
return declaration;
}
public static bool AllDoubleValues(string[] values)
{
double d;
return values.All(val => double.TryParse(val, out d));
}
public static bool AllIntValues(string[] values)
{
int d;
return values.All(val => int.TryParse(val, out d));
}
public static bool AllDateTimeValues(string[] values)
{
DateTime d;
return values.All(val => DateTime.TryParse(val, out d));
}
// add other types if you need...
You can create a command line application from this which can be used in an automated solution.
You can create the dynamic model class from CSV using dynamic in C#. Override TryGetMember of the custom DynamicObject class and use Indexers.
A useful link:
C# Linq to CSV Dynamic Object runtime column name
csv2entity has moved to:
https://github.com/juwikuang/csv2entity
The installation guide is the readme.md file.

C# custom object in combobox

I am relatively new to C# (WinForms), and had a question regarding combo boxes. I have a combo box of Reviewer objects (it is a custom class with an overridden ToString method) and am currently attempting to go through all the checked items and use them to generate a setup file.
Here is how the combo box is populated (populated on form load). Parameters is just a collection of linked lists and parsing code.
for (int i = 0; i < parameters.GetUsers().Count; i++)
{
UserList.Items.Add(parameters.GetUsersArray()[i], parameters.GetUsersArray()[i].isSelected());
}
Here is how I am trying to read it. setup is a StringBuilder. The problem is that GetID is not defined. Does the add function above cast the Reviewer object to a Object object? It looks a little funny since it creates a file fed into a Perl script. A sample desired output line looks like this: inspector0 => "chg0306",
for (int i = 0; i < UserList.CheckedItems.Count; i++)
{
setup.AppendLine("inspector" + i.ToString() + " => \t \"" +
UserList.CheckedItems[i].GetID() + "\",");
}
Here is the users class: (Sample User is ID = aaa0000 name: Bob Joe)
public class Reviewer
{
private string name;
private string id;
private bool selected;
public Reviewer(string newName, string newID, bool newSelected)
{
name = newName;
id = newID;
selected = newSelected;
}
public string GetName()
{
return name;
}
public override string ToString()
{
//string retVal = new string(' ', id.Length + name.Length + 1);
string retVal = id + '\t' + name;
return retVal;
}
public string GetID()
{
return id;
}
public bool isSelected()
{
return selected;
}
}
For posterity, here is the Parameters class:
public class ParameterLists
{
public ParameterLists()
{
projects = new LinkedList<string>();
reviewers = new LinkedList<Reviewer>();
}
public enum FileContents {
PROJECT_LIST,
USERS_LIST,
}
public LinkedList<Reviewer> GetUsers()
{
return reviewers;
}
public LinkedList<string> GetProjects()
{
return projects;
}
public Reviewer[] GetUsersArray()
{
Reviewer[] userArray = new Reviewer[reviewers.Count];
reviewers.CopyTo(userArray, 0);
return userArray;
}
public string[] GetProjectsArray()
{
String[] projectArray = new String[projects.Count];
projects.CopyTo(projectArray, 0);
return projectArray;
}
public void LoadParameters(string fileName)
{
//Reads the parameters from the input file.
}
private void CreateDefaultFile(string fileName)
{
// Create the file from the defaultfile , if it exists.
// Otherwise create a blank default file.
}
private LinkedList <string> projects;
private LinkedList <Reviewer> reviewers;
}
I am probably missing something simple, coming from embedded C++. Any help would be appreciated.
You have to cast that object:
((Reviewer)UserList.CheckedItems[i]).GetID()

write and update key to ini file c#

i want write some setting to ini file with this code that search to find key and update it and if can't find the key add it to file . but it show this error :
"Object reference not set to an instance of an object."
i try this code :
internal class IniData
{
public string Key;
public string Value;
}
internal class IniSection : Dictionary<string, IniData>
{
public string Name { get; set; }
}
internal class IniFile : Dictionary<string, IniSection>
{
public string Path { get; set; }
}
public sealed class IniManager
{
private static readonly Dictionary<string, IniFile> IniFiles;
static IniManager()
{
IniFiles = new Dictionary<string, IniFile>();
}
public static void WriteIni(string fileName, string section, string key, string value)
{
/* Check if ini file exists in the ini collection */
var fileKey = fileName.ToLower();
if (!IniFiles.ContainsKey(fileKey))
{
if (!ImportIni(fileKey))
{
/* Add a new blank file */
var ini = new IniFile { Path = fileName };
IniFiles.Add(fileKey, ini);
}
}
/* Find section */
if (IniFiles[fileKey].ContainsKey(section.ToLower()))
{
/* Find key, if exists replace it */
if (IniFiles[fileKey][section.ToLower()].ContainsKey(key.ToLower()))
{
IniFiles[fileKey][section.ToLower()][key.ToLower()].Value = value;
return;
}
var data = new IniData { Key = key, Value = value };
IniFiles[fileKey][section.ToLower()].Add(key.ToLower(), data);
}
else
{
/* Create new ini section */
var sec = new IniSection { Name = section };
var data = new IniData { Key = key, Value = value };
sec.Add(key.ToLower(), data);
IniFiles[fileKey].Add(section.ToLower(), sec);
}
}
private static bool ImportIni(string fileName)
{
if (!File.Exists(fileName)) { return false; }
string[] data;
try
{
using (var stream = new FileStream(fileName, FileMode.Open))
{
using (var reader = new StreamReader(stream))
{
data = reader.ReadToEnd().Split(new[] { '\r', '\n' }, StringSplitOptions.RemoveEmptyEntries);
reader.Close();
}
stream.Close();
}
}
catch (Exception) { return false; }
if (data.Length == 0) { return false; }
var file = new IniFile { Path = fileName };
var section = new IniSection();
foreach (var s in data)
{
if (s.StartsWith("[") && s.EndsWith("]"))
{
/* Section header */
if (section.Count > 0)
{
/* Add current section */
file.Add(section.Name.ToLower(), section);
}
section = new IniSection { Name = s.Replace("[", null).Replace("]", null) };
continue;
}
/* Using current section, parse ini keys/values */
var iniData = ParseIni(s);
section.Add(iniData.Key.ToLower(), iniData);
}
if (section.Count > 0)
{
/* Add current section */
//##################Erorr : Object reference not set to an instance of an object.
file.Add(section.Name.ToLower(), section);
}
IniFiles.Add(fileName, file);
return true;
}
private static IniData ParseIni(string s)
{
var parts = s.Split('=');
return new IniData { Key = parts[0].Trim(), Value = parts.Length > 1 ? parts[1].Trim() : string.Empty };
}
}
private void button9_Click(object sender, EventArgs e)
{
IniManager.WriteIni("seting.ini", "Sec", "key", "value");
}
Instead of implementing this yourself you should just use the API functions that Windows provide. Of course, if you need to run this on Mono or other platforms than Windows, you need to go back to a pure .NET implementation, but even so I would probably go look for an existing implementation instead of creating that wheel yourself.
Anywhere, here's the API functions:
GetPrivateProfileString
WritePrivateProfileString
Here's an example LINQPad program that uses them:
(hit F4 and paste the following two lines into the additional namespace tab):
System.Runtime.InteropServices
System.ComponentModel
Then try this program:
void Main()
{
var ini = new IniFile(#"d:\temp\test.ini");
ini.WriteValue("Section", "Key", "Value");
ini.ReadValue("Section", "Key").Dump();
ini["Main", "Key2"] = "Test";
ini["Main", "Key2"].Dump();
}
[DllImport("kernel32.dll", CharSet=CharSet.Unicode)]
static extern uint GetPrivateProfileString(string lpAppName, string lpKeyName,string lpDefault, StringBuilder lpReturnedString, uint nSize,string lpFileName);
[DllImport("kernel32.dll", CharSet=CharSet.Unicode, SetLastError=true)]
[return: MarshalAs(UnmanagedType.Bool)]
static extern bool WritePrivateProfileString(string lpAppName, string lpKeyName, string lpString, string lpFileName);
public class IniFile
{
const int MAX_SIZE = 1024;
private readonly string _FilePath;
public IniFile(string filePath)
{
if (filePath == null)
throw new ArgumentNullException("filePath");
_FilePath = filePath;
}
public string this[string section, string key]
{
get
{
return ReadValue(section, key);
}
set
{
WriteValue(section, key, value);
}
}
public string ReadValue(string section, string key, string defaultValue = null)
{
var result = new StringBuilder(MAX_SIZE);
if (GetPrivateProfileString(section, key, defaultValue ?? string.Empty, result, (uint)result.Capacity, _FilePath) > 0)
return result.ToString();
throw new Win32Exception();
}
public void WriteValue(string section, string key, string value)
{
if (!WritePrivateProfileString(section, key, value, _FilePath))
throw new Win32Exception();
}
}
The problem here is that if the file starts with a key and not with a section, the foreach doesn't match the if (s.StartsWith("[") && s.EndsWith("]")) at all and so the Section.Name is never set, thus it is null when called in file.Add(section.Name.ToLower(), section);
BTW: your code seems quite buggy, try to redesign it at least in the main foreach of ImportIni

Adding a number suffix when creating folder in C#

I'm trying to handle if the folder i want to create is already exist .. to add a number to folder name .. like windows explorer .. e.g(New Folder , New Folder 1 , New Folder 2 ..)
how can i do it recursively
i know this code is wrong.
how can i fix or maybe change the code below to solve the problem ?
int i = 0;
private void NewFolder(string path)
{
string name = "\\New Folder";
if (Directory.Exists(path + name))
{
i++;
NewFolder(path + name +" "+ i);
}
Directory.CreateDirectory(path + name);
}
For this, you don't need recursion, but instead should look to an iterative solution:
private void NewFolder(string path) {
string name = #"\New Folder";
string current = name;
int i = 1;
while (Directory.Exists(Path.Combine(path, current))) {
i++;
current = String.Format("{0}{1}", name, i);
}
Directory.CreateDirectory(Path.Combine(path, current));
}
private void NewFolder(string path)
{
string name = #"\New Folder";
string current = name;
int i = 0;
while (Directory.Exists(path + current))
{
i++;
current = String.Format("{0} {1}", name, i);
}
Directory.CreateDirectory(path + current);
}
credit for #JaredPar
The simpliest way to do it is:
public static void ebfFolderCreate(Object s1)
{
DirectoryInfo di = new DirectoryInfo(s1.ToString());
if (di.Parent != null && !di.Exists)
{
ebfFolderCreate(di.Parent.FullName);
}
if (!di.Exists)
{
di.Create();
di.Refresh();
}
}
You can use this DirectoryInfo extender:
public static class DirectoryInfoExtender
{
public static void CreateDirectory(this DirectoryInfo instance)
{
if (instance.Parent != null)
{
CreateDirectory(instance.Parent);
}
if (!instance.Exists)
{
instance.Create();
}
}
}

Categories

Resources