Adding gsm sms to textbox or listbox (WinForm) - c#

I have these codes for receiving sms from my gsm modem. It works but I want the messages to be viewed on a listbox or textbox. Can someone help me on how to do this?
public void Read()
{
gsmPort.WriteLine("AT+CMGF=1"); // Set mode to Text(1) or PDU(0)
Thread.Sleep(1000); // Give a second to write
gsmPort.WriteLine("AT+CPMS=\"SM\""); // Set storage to SIM(SM)
Thread.Sleep(1000);
gsmPort.WriteLine("AT+CMGL=\"ALL\""); // What category to read ALL, REC READ, or REC UNREAD
Thread.Sleep(1000);
gsmPort.Write("\r");
Thread.Sleep(1000);
string response = gsmPort.ReadExisting();
if (response.EndsWith("\r\nOK\r\n"))
{
Console.WriteLine(response);
// add more code here to manipulate reponse string.
}
else
{
// add more code here to handle error.
Console.WriteLine(response);
}
This is how I communicate with my modem using these codes. It works but only on console. I want add these to my winform
class GSMsms
{
private SerialPort gsmPort = null;
private bool IsDeviceFound { get; set; } = false;
public bool IsConnected { get; set; } = false;
public GSMsms()
{
gsmPort = new SerialPort();
}
public GSMcom[] List()
{
List<GSMcom> gsmCom = new List<GSMcom>();
ConnectionOptions options = new ConnectionOptions();
options.Impersonation = ImpersonationLevel.Impersonate;
options.EnablePrivileges = true;
string connString = $#"\\{Environment.MachineName}\root\cimv2";
ManagementScope scope = new ManagementScope(connString, options);
scope.Connect();
ObjectQuery query = new ObjectQuery("SELECT * FROM Win32_POTSModem");
ManagementObjectSearcher search = new ManagementObjectSearcher(scope, query);
ManagementObjectCollection collection = search.Get();
foreach (ManagementObject obj in collection)
{
string portName = obj["AttachedTo"].ToString();
string portDescription = obj["Description"].ToString();
if (portName != "")
{
GSMcom com = new GSMcom();
com.Name = portName;
com.Description = portDescription;
gsmCom.Add(com);
}
}
return gsmCom.ToArray();
}

Related

Start/Stop BizTalk Send port in C# with WMI

Is it possible to start/stop the send the port using MSBTS_SendPort class through C#?
I have got the port details and the status using Windows WMI and trying to Start/Stop the port
public bool CheckSendPorts()
{
bool returnValue = true;
UserName = "";
Password = "";
ServerName = "testserver";
using (ManagementObjectSearcher searcher = GetWmiSearcher(UserName,Password,ServerName, WMI_SCOPE, $"SELECT * FROM MSBTS_SendPort where Name = 'testSendPort'"))
{
if (searcher == null)
{
//WriteOutput($"No Send Ports found.", true);
return false;
}
foreach (ManagementObject instanceObject in searcher.Get())
{
string portName = instanceObject["Name"] as string;
uint portState = (uint)instanceObject["Status"];
string portStatus = GetPortStatus((uint)instanceObject["Status"]);
bool ignoreLocation = false;
}
}
return returnValue;
}
internal ManagementObjectSearcher GetWmiSearcher(string username,string password,string servername, string wmiScope, string wmiQuery)
{
ConnectionOptions connectionOptions = new ConnectionOptions();
connectionOptions.Authentication = AuthenticationLevel.PacketPrivacy;
if (!string.IsNullOrEmpty(username))
{
connectionOptions.Username = username;
connectionOptions.Password = password;
}
else
{
connectionOptions.Impersonation = ImpersonationLevel.Impersonate;
}
ManagementScope scope = new ManagementScope($#"\\{servername}{wmiScope}");
scope.Options = connectionOptions;
EnumerationOptions enumOptions = new EnumerationOptions();
enumOptions.ReturnImmediately = false;
SelectQuery query = new SelectQuery(wmiQuery);
return new ManagementObjectSearcher(scope, query, enumOptions);
}
private string GetPortStatus(uint code)
{
switch (code)
{
case 1:
return "Bound";
case 2:
return "Stopped";
case 3:
return "Started";
default:
return "Unknown";
}
}
Microsoft documentation suggest there is an method as MSBTS_SendPort.Stop to stop the port. Is it possible?
You can invoke the "stop" or "start" method in your foreach loop while iterating through the instances.
foreach (ManagementObject instanceObject in searcher.Get())
{
string portName = instanceObject["Name"] as string;
uint portState = (uint)instanceObject["Status"];
string portStatus = GetPortStatus((uint)instanceObject["Status"]);
bool ignoreLocation = false;
//invoke method stop with an empty object array for parameters (because this method doesn't take any parameters.
instanceObject.InvokeMethod("stop", new object[]{ });
}

Determine from which location an application was being started

Is there any possibility to determine how a c# application was being started?
In my case I want to check if this application (wpf) is being started by a shortcut located in a specific folder.
So, there are two ways to open my application
using direct shortcut
starting another application which is like an update manager to keep my application up to date. After checking, it starts my application with Process.Start()
And I want to ensure that the application is only able to be started with the update manager.
A trick you could use is to check the parent's PID, and then get some of the parent's process information.
If the parent's process name is something like "explorer.exe" then the application was started from the shortcut or directly by double-clicking it on explorer.
Otherwise, it was started from another application: it could be your updater application, it could also be another application with the same name as your updater application...
This means you have to re-think how deep you want to go for such a solution, and how deep do you want security control. You could pass arguments from your updater to your main application, or implement some inter-process communication with token exchanges... it is impossible to make a 100% secure system.
As someone commented above, this seems like a XY problem... or maybe not. Maybe it is just a security concern. It's recommended to revise what exactly are you aiming for this software.
In case you need sample code for retrieving process information in .NET (by using System.Management), then just give a try to the code listed below. All you have to do is to place it in a console application project named 'Updater', and correctly set the path to your main application in the code.
If you play a little bit with this example by starting and closing YourApplication.exe in different situations, then you should be able to see an output like this:
Parent process 'Updater.exe' [PID=5472]
Parent process 'explorer.exe' [PID=12052]
The code below was tested on VS2017 .Net 4.6.1
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Management;
class Program
{
static void Main(string[] args)
{
Process.Start(new ProcessStartInfo()
{
FileName = "YourApplication.exe" // path to your application
});
while (Console.ReadKey(true).Key != ConsoleKey.Escape)
{
Process process = Process.GetProcessesByName("YourApplication").FirstOrDefault(); // your application's process name
if (process == null)
{
Console.WriteLine($"Process is not running...");
continue;
}
ProcessManager pm = ProcessManager.FromLocalMachine();
var processProperties = pm.GetProcessProperties(process.Id);
int parentProcessId = Convert.ToInt32(processProperties[EProcessProperty.ParentProcessId]);
try
{
var parentProcessProperties = pm.GetProcessProperties(parentProcessId);
string parentProcessName = parentProcessProperties[EProcessProperty.Name].ToString();
Console.WriteLine($"Parent process '{parentProcessName ?? "Unknown"}' [PID={parentProcessId}]");
Console.WriteLine("---------------------------------");
}
catch { Console.WriteLine("Parent process information not found."); }
}
}
}
public class ProcessConnection
{
internal ManagementScope ManagementScope { get; }
internal ProcessConnection(string machineName, string user = null, string password = null, string domain = null)
{
ManagementScope = new ManagementScope
{
Path = new ManagementPath(#"\\" + machineName + #"\root\CIMV2"),
Options = new ConnectionOptions
{
Impersonation = ImpersonationLevel.Impersonate,
Authentication = AuthenticationLevel.Default,
EnablePrivileges = true,
Username = user == null ? null : (string.IsNullOrWhiteSpace(domain) ? user : $"{domain}\\{user}"),
Password = user == null ? null : password,
},
};
ManagementScope.Connect();
}
}
public class ProcessManager
{
public static ProcessManager FromLocalMachine() => new ProcessManager()
{
Machine = Environment.MachineName,
};
public static ProcessManager FromRemoteMachine(string machine, string user = null, string password = null, string domain = null) => new ProcessManager()
{
Machine = machine,
User = user,
Password = password,
Domain = domain,
};
private ProcessManager() { }
public string Machine { get; private set; }
public string User { get; private set; }
public string Password { get; private set; }
public string Domain { get; private set; }
private ProcessConnection Connection { get; set; }
private ManagementScope ManagementScope => Connection == null ? (Connection = new ProcessConnection(Machine, User, Password, Domain)).ManagementScope : Connection.ManagementScope;
public EProcessStartStatus StartProcess(string processPath)
{
ManagementClass mc = new ManagementClass($"\\\\{Machine}\\root\\CIMV2", "Win32_Process", null);
ManagementBaseObject process = mc.GetMethodParameters("Create");
process["CommandLine"] = processPath;
ManagementBaseObject createCode = mc.InvokeMethod("Create", process, null);
string createCodeStr = createCode["ReturnValue"].ToString();
return (EProcessStartStatus)Convert.ToInt32(createCodeStr);
}
public bool KillProcess(string processName)
{
try
{
SelectQuery query = new SelectQuery($"SELECT * FROM Win32_Process WHERE Name = '{processName}'");
ManagementObjectSearcher searcher = new ManagementObjectSearcher(ManagementScope, query);
foreach (ManagementObject mo in searcher.Get()) mo.InvokeMethod("Terminate", null);
return true;
}
catch { return false; }
}
public bool KillProcess(int processId)
{
try
{
SelectQuery query = new SelectQuery($"SELECT * FROM Win32_Process WHERE ProcessId = '{processId}'");
ManagementObjectSearcher searcher = new ManagementObjectSearcher(ManagementScope, query);
foreach (ManagementObject mo in searcher.Get()) mo.InvokeMethod("Terminate", null);
return true;
}
catch { return false; }
}
public void SetProcessPriority(string processName, EProcessPriority priority)
{
SelectQuery query = new SelectQuery($"SELECT * FROM Win32_Process WHERE Name = '{processName}'");
ManagementObjectSearcher managementObjectSearcher = new ManagementObjectSearcher(ManagementScope, query);
foreach (ManagementObject managementObject in managementObjectSearcher.Get())
{
ManagementBaseObject methodParams = managementObject.GetMethodParameters("SetPriority");
methodParams["Priority"] = priority;
managementObject.InvokeMethod("SetPriority", methodParams, null);
}
}
public string GetProcessOwner(string processName)
{
SelectQuery query = new SelectQuery($"SELECT * FROM Win32_Process WHERE Name = '{processName}'");
ManagementObjectSearcher searcher = new ManagementObjectSearcher(ManagementScope, query);
foreach (ManagementObject mo in searcher.Get())
{
ManagementBaseObject methodParams = mo.GetMethodParameters("GetOwner");
ManagementBaseObject owner = mo.InvokeMethod("GetOwner", null, null);
return owner["User"].ToString();
}
return null;
}
public string GetProcessOwnerSID(string processName)
{
SelectQuery query = new SelectQuery($"SELECT * FROM Win32_Process WHERE Name = '{processName}'");
ManagementObjectSearcher searcher = new ManagementObjectSearcher(ManagementScope, query);
foreach (ManagementObject mo in searcher.Get())
{
ManagementBaseObject methodParams = mo.GetMethodParameters("GetOwnerSid");
ManagementBaseObject OwnerSid = mo.InvokeMethod("GetOwnerSid", null, null);
return OwnerSid["Sid"].ToString();
}
return null;
}
public IList<int> GetRunningProcesses()
{
IList<int> processes = new List<int>();
SelectQuery query = new SelectQuery("SELECT * FROM Win32_Process");
ManagementObjectSearcher searcher = new ManagementObjectSearcher(ManagementScope, query);
foreach (ManagementObject mo in searcher.Get()) processes.Add(int.Parse(mo["ProcessId"].ToString()));
return processes;
}
public IDictionary<EProcessProperty, object> GetProcessProperties(int processId)
{
SelectQuery query = new SelectQuery($"SELECT * FROM Win32_Process WHERE ProcessId = '{processId}'");
ManagementObjectSearcher searcher = new ManagementObjectSearcher(ManagementScope, query);
Dictionary<EProcessProperty, object> properties = new Dictionary<EProcessProperty, object>();
foreach (ManagementObject mo in searcher.Get())
{
foreach (PropertyData pd in mo.Properties)
{
if (Enum.TryParse(pd.Name, out EProcessProperty e)) properties[e] = pd.Value;
else Console.WriteLine(pd.Name + " is not mapped in the properties enumeration.");
}
}
return properties;
}
public IDictionary<EProcessProperty, object> GetProcessProperties(string processName)
{
SelectQuery query = new SelectQuery($"SELECT * FROM Win32_Process WHERE Name = '{processName}'");
ManagementObjectSearcher searcher = new ManagementObjectSearcher(ManagementScope, query);
Dictionary<EProcessProperty, object> properties = new Dictionary<EProcessProperty, object>();
foreach (ManagementObject mo in searcher.Get())
{
foreach (PropertyData pd in mo.Properties)
{
if (Enum.TryParse(pd.Name, out EProcessProperty e)) properties[e] = pd.Value;
else Console.WriteLine(pd.Name + " is not mapped in the properties enumeration.");
}
}
return properties;
}
public IList<int> GetProcessessFromExecutablePath(string executablePath)
{
SelectQuery query = new SelectQuery($"SELECT * FROM Win32_Process WHERE ExecutablePath = '{executablePath.Replace("\\", "\\\\")}'");
ManagementObjectSearcher searcher = new ManagementObjectSearcher(ManagementScope, query);
return searcher.Get().Cast<ManagementObject>().Select(mo => Convert.ToInt32(mo["ProcessId"])).ToList();
}
}
public enum EProcessPriority : uint
{
IDLE = 0x40,
BELOW_NORMAL = 0x4000,
NORMAL = 0x20,
ABOVE_NORMAL = 0x8000,
HIGH_PRIORITY = 0x80,
REALTIME = 0x100
}
public enum EProcessStartStatus
{
Success = 0,
AccessDenied = 2,
NoPermissions = 3,
Unknown = 8,
FileNotFound = 9,
Invalid = 21,
}
public enum EProcessProperty
{
Caption,
CommandLine,
CreationClassName,
CreationDate,
CSCreationClassName,
CSName,
Description,
ExecutablePath,
ExecutionState,
Handle,
HandleCount,
InstallDate,
KernelModeTime,
MaximumWorkingSetSize,
MinimumWorkingSetSize,
Name,
OSCreationClassName,
OSName,
OtherOperationCount,
OtherTransferCount,
PageFaults,
PageFileUsage,
ParentProcessId,
PeakPageFileUsage,
PeakVirtualSize,
PeakWorkingSetSize,
Priority,
PrivatePageCount,
ProcessId,
QuotaNonPagedPoolUsage,
QuotaPagedPoolUsage,
QuotaPeakNonPagedPoolUsage,
QuotaPeakPagedPoolUsage,
ReadOperationCount,
ReadTransferCount,
SessionId,
Status,
TerminationDate,
ThreadCount,
UserModeTime,
VirtualSize,
WindowsVersion,
WorkingSetSize,
WriteOperationCount,
WriteTransferCount,
}
If there are only 2 ways of starting your app, the second method should pass a parameter (a GUID?) to Process.Start() - generated by your updater app.
Maybe devise some kind of algorithm that allows the app to start only with the token.
From what I know this is impossible in the way you would like it to be but there's one trick which you can use. Firstly change your WPF application's entry method to get the command line arguments, and ( for example ) use -u argument to distinct from where the application was started. Then after -u you can pass a HWND or a process ID that matches your updater. Of course you have to then check if that application is running and if it's your updater.
example :
// updated process start
ProcessStartInfo psi = new ProcessStartInfo("your/WPF/application.exe");
psi.Arguments = "-u " + Process.GetCurrentProcess().Id;
// fill up rest of the properties you need
Process.Start(psi);
// wpf application's entry point
void Main(string[] args)
{
string updaterProcessIdstr = string.Empty;
for (int i = 0; i < args.Length; i++)
{
if(args[i] == "-u")
{
updaterProcessIdstr = args[i + 1];
i++;
}
}
int pid = int.Parse(updaterProcessIdstr);
Process updaterProcess = Process.GetProcessById(pid);
// do some validation here
// send something to stdin and read from stdout
// to determine if it was started from that updater.
}

C#: Arduino not recognized after Windows 10 upgrade

Please check the code that I am using:
public static string AutoDetectArduinoPort()
{
ConnectionOptions options = PrepareOptions();
ManagementScope scope = PrepareScope(Environment.MachineName, options, #"\root\CIMV2");
// Prepare the query and searcher objects.
ObjectQuery objectQuery = new ObjectQuery("SELECT * FROM Win32_PnPEntity WHERE ConfigManagerErrorCode = 0");
ManagementObjectSearcher portSearcher = new ManagementObjectSearcher(scope, objectQuery);
using (portSearcher)
{
string portName = "";
foreach (ManagementObject currentObject in portSearcher.Get())
{
if (currentObject != null)
{
object currentObjectCaption = currentObject["Caption"];
if (currentObjectCaption != null)
{
portName = currentObjectCaption.ToString();
if (portName.Contains("(COM"))
{
if (portName.Contains("Arduino")) // e.g. "Arduino Mega 2560 (COM3)"
{
portName = portName.Substring(portName.LastIndexOf("(COM")).Replace("(", string.Empty).Replace(")", string.Empty);
return portName;
}
}
}
}
}
}
return null;
}
And i call it like this:
string portName = AutoDetectArduinoPort();
MessageBox.Show(portName); // shows "COM3"
if (portName != null)
{
serialPort.PortName = portName;
serialPort.Open();
......
Runtime exception (System.IO.IOException) is thrown at this last line saying that "The port 'COM3' does not exist." while it is showing in Device Manager and all.
What am i doing wrong? Please help me fix this prob. Irony is that it was working all fine before windows 10 upgrade :(

Is creating an EPT (MS PS Enteprise Project Type) via PSI/CSOM possible?

The following code does not throw any exception but it also doesn't create a new EPT:
public void CreateEnterpriseProjectType(Guid eptGuid, string eptName, string eptDescription)
{
ProjectContext pwaContext = new ProjectContext("http://serverName/pwaName");
pwaContext.Credentials = new NetworkCredential("adminUsername", "adminPassword", "domainName");
EnterpriseProjectTypeCreationInformation eptData = new EnterpriseProjectTypeCreationInformation();
eptData.Id = eptGuid;
eptData.Name = eptName;
eptData.Description = eptDescription;
eptData.IsDefault = false;
eptData.IsManaged = true;
eptData.WorkspaceTemplateName = "PROJECTSITE#0";
eptData.ProjectPlanTemplateId = Guid.Empty;
eptData.WorkflowAssociationId = Guid.Empty;
// Get the maximum order of the existing EPTs and increment by 1 in order to use an order that does not already exist
eptData.Order = Convert.ToInt32(Database.GetValue("SELECT MAX(ENTERPRISE_PROJECT_TYPE_ORDER) FROM [ProjectWebApp].[pub].[MSP_ENTERPRISE_PROJECT_TYPES]")) + 1;
pwaContext.Load(pwaContext.ProjectDetailPages);
pwaContext.ExecuteQuery();
List<ProjectDetailPageCreationInformation> projectDetailPages = new List<ProjectDetailPageCreationInformation>() {new ProjectDetailPageCreationInformation() { Id = pwaContext.ProjectDetailPages[1].Id, IsCreate = false }};
eptData.ProjectDetailPages = projectDetailPages;
EnterpriseProjectType newEpt = pwaContext.EnterpriseProjectTypes.Add(eptData);
pwaContext.EnterpriseProjectTypes.Update();
}
Any ideas on what I'm doing wrong or what I'm missing? Is it possible to create an EPT programmatically?
Yes, it is possible to create an EPT programmatically. Turns out three things were missing:
A second PDP having IsCreate = true (at least one with IsCreate = true and one with IsCreate = false are required for successfully creating an EPT)
A query for iterating through the existing EPTs before adding a new one:
pwaContext.Load(pwaContext.EnterpriseProjectTypes);
pwaContext.ExecuteQuery();
A pwaContext.ExecuteQuery(); after the pwaContext.EnterpriseProjectTypes.Update(); command.
The following code works fine for me:
public class PSI
{
private ProjectContext _context;
private string basicEpt = "Enterprise Project"; // Basic enterprise project type.
private static readonly PSI psi = new PSI();
private int timeoutSeconds = 60;
SvcProject.ProjectClient _prClient;
private PSI ()
{
_context = new ProjectContext(System.Configuration.ConfigurationManager.AppSettings["PwaUrl"]);
//credentials of currently running acount or enable line below
//_context.Credentials = new System.Net.NetworkCredential("user", "pass", "domain");
timeoutSeconds = int.Parse(System.Configuration.ConfigurationManager.AppSettings["DefaultTimeoutPwa"]);
_prClient = new SvcProject.ProjectClient("basicHttp_Project");
}
public static PSI Instance
{
get{ return psi; }
}
public Guid GetEptUid(string eptName)
{
Guid eptUid = Guid.Empty;
try
{
var eptList = _context.LoadQuery( _context.EnterpriseProjectTypes.Where(ept => ept.Name == eptName));
_context.ExecuteQuery();
eptUid = eptList.First().Id;
}
catch (Exception ex)
{
string msg = string.Format("GetEptUid: eptName = \"{0}\"\n\n{1}", eptName, ex.GetBaseException().ToString());
throw new ArgumentException(msg);
}
return eptUid;
}
public PublishedProject CreateProject(string prName, string description, DateTime startDate)
{
try
{
System.Console.Write("\nCreating project: {0} ...", prName);
ProjectCreationInformation newProj = new ProjectCreationInformation();
newProj.Id = Guid.NewGuid();
newProj.Name = prName;
newProj.Description = description;
newProj.Start = startDate;
newProj.EnterpriseProjectTypeId = GetEptUid(basicEpt);
PublishedProject newPublishedProj = _context.Projects.Add(newProj);
QueueJob qJob = _context.Projects.Update();
JobState jobState = _context.WaitForQueue(qJob, timeoutSeconds);
if (jobState == JobState.Success)
return newPublishedProj;
else
return null;
}
catch (Exception ex)
{
System.Console.ForegroundColor = ConsoleColor.Red;
System.Console.WriteLine("\nError: {0}", ex.Message);
System.Console.ResetColor();
return null;
}
}
}

Get user login name in C#

How to check login user name from the system in c#
I tried it using this method
static string whoisLoggedIn(string HostOrIP)
{
GUFlag = true;
HostOrIP = Environment.MachineName;
System.Management.ConnectionOptions myConnectionOptions = new System.Management.ConnectionOptions();
myConnectionOptions.Impersonation = System.Management.ImpersonationLevel.Impersonate;
System.Management.ManagementScope objwmiservice;
System.Management.ManagementObjectSearcher myObjectSearcher2;
System.Management.ManagementObjectCollection myCollection2;
try
{
objwmiservice = new System.Management.ManagementScope(("\\\\" + (HostOrIP +
"\\root\\cimv2")), myConnectionOptions);
objwmiservice.Connect();
myObjectSearcher2 = new System.Management.ManagementObjectSearcher(objwmiservice.Path.ToString(),
"Select UserName from Win32_ComputerSystem");
myObjectSearcher2.Options.Timeout = new TimeSpan(0, 0, 0, 0, 7000);
myCollection2 = myObjectSearcher2.Get();
GUFlag = false;
foreach (System.Management.ManagementObject myObject in myCollection2)
{
if (!(myObject.GetPropertyValue("Username") == null))
{
string Userx = myObject.GetPropertyValue("Username").ToString();
int posx = Userx.LastIndexOf("\\");
if ((posx > 0))
{
Userx = Userx.Substring((posx + 1));
return Userx.ToUpper();
}
}
}
return "<Nobody>";
}
catch (Exception)
{
return "<Nobody>";
}
finally {
GUFlag = false;
}
}
But the problem is some time deadlock occur on myObjectSearcher2.Get();
Is there any way available to get login username
did you try that?
Environment.UserName
it will give you the user name of the user currently login on windows
EDIT
I found this bit of code here http://www.debugging.com/bug/20243, it may solve your issue.
solution by using WMI ( http://msdn.microsoft.com/en-us/library/system.management.aspx ):
private string GetUserName()
{
string result = "";
using (ManagementObjectSearcher searcher = new ManagementObjectSearcher("SELECT UserName, Name FROM Win32_ComputerSystem"))
{
foreach (ManagementObject mo in searcher.Get())
{
if (mo["UserName"] != null)
result = mo["UserName"].ToString();
if (mo["Name"] != null)
result += " (" + mo["Name"].ToString() + ")";
}
}
return result;
}
Unless I'm not understanding you correctly, I believe it's just:
using System.Security.Principal;
this.nametext = WindowsIdentity.GetCurrent().Name;

Categories