How can I align my text in the terminal? (Java) - java

My code accepts 3 arguments, first (args[0]) is the text file, second (args1) is the number of characters per line and the final argument (args[2]) is not yet implemented but is the option of the alignment (Left, Center or Justify).
Right now, I am trying to implement the left alignment and here is my code (the alignment code comes the last):
try {
System.out.println("usage: java AlignText" + args[0] + " " + args[1] + "
" + args[2]);
String[] text = FileUtil.readFile(args[0]);
int paragraphs = Integer.parseInt(args[1]);
StringBuilder builder = new StringBuilder();
for (String string : text) {
if (builder.length() > 0) {
builder.append(" ");
}
builder.append(string);
}
String str = builder.toString();
StringBuilder sb = new StringBuilder();
int i = str.indexOf(" ",paragraphs);
while (i>0){
sb.append(str.substring(0, i).trim());
sb.append("\n");
str = str.substring(i);
if(str.length()>paragraphs){
i = str.indexOf(" ", paragraphs);
}
else {
i = -1;
}
}
sb.append(str.trim());
sb.toString();
//System.out.println(sb.length());
String[] lines = new String[100];
int count = 0;
int index = 0;
for(int j=0;j<sb.length();j++){
if(sb.charAt(j) == '\n') {
lines[index] = sb.substring(count,j).trim();
System.out.printf("%20s"+"\n", lines[index]);
//System.out.println("\n");
count = j;
index++;
}
}
And here is my output:

Related

handle 1gb data file to read words and calculate max length word?

i wrote this code but its going to fail on 1gb size file.
public class TestFiles {
public static void main(String[] args) {
int minLength = Integer.MAX_VALUE;
int maxLength = Integer.MIN_VALUE;
String minWord = "";
String maxWord = "";
List<String> words = new ArrayList<>();
try {
File myObj = new File("C:\\Users\\Downloads\\java.txt");
Scanner myReader = new Scanner(myObj);
while (myReader.hasNextLine()) {
String data = myReader.nextLine();
String[] dataArray = data.split(" ");
List<String> list = Arrays.asList(dataArray);
for (String s : list) {
if (s.length() < minLength) {
minLength = s.length();
minWord = s;
} else if (s.length() > maxLength) {
maxLength = s.length();
maxWord = s;
}
}
}
myReader.close();
} catch (Exception e) {
// TODO: handle exception
}
System.out.println("min length " + minLength + " - max lenth " + maxLength);
System.out.println("min length word " + minWord + " - max lenth word " + maxLength);
}
}
could you please answers? how can i solve this?
The problem gets obvious, when 1gb words are squashed into 1 line!*
Solution: Not to process the input "line-wise", but "word-wise", which is suf- & efficient! ;)
Voila:
public class TestFiles {
public static void main(String[] args) {
int minLength = Integer.MAX_VALUE;
int maxLength = Integer.MIN_VALUE;
String minWord = "";
String maxWord = "";
try {
File myObj = new File("C:\\Users\\Downloads\\java.txt");
Scanner myReader = new Scanner(myObj);
while (myReader.hasNext()) {
String word = myReader.next();
if (word.length() < minLength) {
minLength = word.length();
minWord = word;
}
if (word.length() > maxLength) {
maxLength = word.length();
maxWord = word;
}
}
}
myReader.close();
} catch (Exception e) {
// TODO: handle exception
}
System.out.println("min length " + minLength + " - max lenth " + maxLength);
System.out.println("min length word " + minWord + " - max lenth word " + maxLength);
}
}
*when "many" words are in one line, then we could get problems here:
myReader.hasNextLine(),
String data = myReader.nextLine() and
String[] dataArray = data.split(" ");
#huy's answer also correct: the else is "efficient for most cases", but is "incorrect for corner cases".
int len = s.length();
if (len < minLength) {
minLength = len;
minWord = s;
}
if (len > maxLength) {
maxLength = len;
maxWord = s;
}
Your test case will fail if large string is located at first index of first line.
Btw, I think you should break your big test to small test, try to find small string and large string for single line, after that multi lines and data from files

Reading & Breaking CSV File in Java:

I am editing this question to be more specific and I've learned some Jave to find the solution to my problem. I have a file in CSV format like this:
or in excel like this:
Now I am using Java program to read the second line of file and separate each Comma Separated Value and write it to console as well as on other output file and it was done easily. Now I'm trying to break the last value of:
S/1,M/1,L/1,XL/1 | 2XL/1,3XL/1,4XL/1,5XL/1 | MT/1,LT/1 (Original)
S/1,M/1,L/1,XL/1,2XL/1,3XL/1,4XL/1,5XL/1,MT/1,LT/1 (Modified using program to remove spaces and replacing the Pipes (|) with comma.
In each value, There is the size name before Forward Slash (/) and its quantity is after that. What I'm trying is using the Forward Slash (/) to separate the size with its quantity. And the problem is that the size may contain the forward slash as well (e.g. 12/BT or 2BT/2x). I've tried many algorithms like reversing the whole array or storing the slash count but not getting the success. The whole code to read file and break the comma separated values into separate columns of file is as following:
import java.io.*;
import javax.swing.*;
public class ReadFile3c{
public static void main(String args[]){
try{
//Getting File Name
String fileName = JOptionPane.showInputDialog("Enter File Name") + ".csv";
//Creating Stream with File
FileReader fr = new FileReader(fileName);
//Applying Buffer Filter
BufferedReader br = new BufferedReader(fr);
//Reading First line then Second Line
String s = br.readLine();
s = br.readLine();
s = s + ",";//adding comma at the end of the file
s = s.replaceAll("\\s",""); //Eliminating Spaces
s = s.replaceAll("\\|",","); //Replacing Pipes with comma
char charArray[] = s.toCharArray();
//Declaring Strings and variablse for value separating function
int n = 0; //Array Variable
int m = 0; //Array Variable
String[] inverted = new String[3]; //String to store inverted Commas Values
String[] comma = new String[10]; //String to store comma Values
String value = ""; //Storing character values
try{
//Loop to cycle each character of file
for(int j = 0; j<charArray.length;j++){
//Inverted comma value separator
if (charArray[j] == '"') {
j++;
//loop to gather values b/w invreted comma
while((charArray[j] != '"')){
value = value + charArray[j];
j++;
}
inverted[n] = value;
n++;
j++;
value = "";
}else{
j = j - 1;
//comma Value separator
if (charArray[j] == ','){
j++;
//loop to gether values b/w commas
while((charArray[j] !=',')){
value = value + charArray[j];
j++;
}
comma[m] = value;
m++;
value = "";
}
}
}
}catch(Exception ex){
System.out.println("in inner Exception Block" + ex);
}
//declaring variables to storing values
String name, patternCode, placeSizeQty,width,length,utill,pArea,pPerimeter,totalPcs,placePcs,tSizes;
name = inverted[0];
patternCode = inverted[1];
placeSizeQty = inverted[2];
width = comma[0];
length = comma[1];
utill = comma[2];
pArea = comma[3];
pPerimeter = comma[4];
totalPcs = comma[5];
placePcs = comma[6];
tSizes = comma[7];
//printing all values on Console
System.out.println("\nMarkerName: " + name);
System.out.println("Width :" + width);
System.out.println("Length :" + length);
System.out.println("Utill :" + utill);
System.out.println("Place Area :" + pArea);
System.out.println("Place Perimeter :" + pPerimeter);
System.out.println("PatternCode: " + patternCode);
System.out.println("PlaceSizeQty: " + placeSizeQty);
System.out.println("Total Pcs :" + totalPcs);
System.out.println("Place Pcs :" + placePcs);
System.out.println("Total Sizes :" + tSizes);
//Creating Output file
String fileOutput = JOptionPane.showInputDialog("Enter Output File Name") + ".txt";
//File Writer
try{
//Creating Stream with output file
FileWriter fw = new FileWriter(fileOutput);
//Applying Buffring Stream
PrintWriter pw = new PrintWriter(fw);
//Declaration
String outputLine = null;
//Writing Inverted inputs
for (int u = 0; u <=2 ;u++ ) {
outputLine = inverted[u];
pw.println(outputLine);
System.out.println("Writing: " + outputLine);
}//end of for
//writing comma inputs
for (int t = 0;t <=7 ; t++ ) {
outputLine = comma[t];
pw.println(outputLine);
System.out.println("Writing: " + outputLine);
}//end of for
pw.flush();
pw.close();
fw.close();
fr.close();
br.close();
}catch(Exception ex){
System.out.println("Output: " + ex);
}//End of output catch
}catch(IOException ex){
System.out.println(ex);
}//end of catch
}//end of catch
}//end of Class
And the code to Break the Size and quantity and store it in Double array (Not completed) is as Following:
import java.io.*;
import javax.swing.*;
public class ReadFileInvert{
public static void main(String args[]){
try{
String fileName = JOptionPane.showInputDialog("Enter File Name") + ".csv";
FileReader fr = new FileReader(fileName);
BufferedReader br = new BufferedReader(fr);
String s = br.readLine();
System.out.println(s);
s = s.replaceAll("\\s","");
s = s.replaceAll("\\|",",");
System.out.println(s);
char charArray[] = s.toCharArray();
char charArrayI[] = new char[charArray.length + 1];
int j = 0;
String value = "";
for(int i = charArray.length; i > 0; i--){
charArrayI[j] = charArray[i];
value = value + charArrayI[j];
j++;
}
System.out.println("1" + value);
}catch(Exception ex){
System.out.println(ex);
}
}
}
Now in simple I just want to Separate the sizes (Which may contains the Forward Slashes) with its quantity (After last slash of each value) and store it in double array Like charArray[sizeName][Qty]. Sorry if i didn't explained my problem well as I'm Learning the Coding. but I'll provide as much info as you want.
Have you considered looking at the CAD software export to see if there is a solution on the file creation side? Or is this file coming from a third party?
OK. So, after the hard work of whole day, I've found the following solution to my problem:
import java.io.*;
import javax.swing.*;
public class ReadFileInvert2{
public static void main(String args[]){
try{
String fileName = JOptionPane.showInputDialog("Enter File Name") + ".csv";
FileReader fr = new FileReader(fileName);
BufferedReader br = new BufferedReader(fr);
String s = br.readLine();
System.out.println(s);
s = s.replaceAll("\\s","");
s = s.replaceAll("\\|",",");
System.out.println(s);
char charArray[] = s.toCharArray();
int x = charArray.length - 1;
charArray[x] = ',';
int no = 1;
int size = 1;
int qty = 2;
String sizeS = "";
String qtyS = "";
//String resSet[][] = new String[4][2];
String resSize[] = new String[20];
String resQty[] = new String[20];
int slashNo = 0;
String value = "";
for (int j = 1; j < charArray.length; j++){
int n = j;
if (charArray[j] == ','){
j++;
}
while (charArray[j] != ','){
if (charArray[j] == '/') {
slashNo = j;
//j++;
}
value = value + charArray[j];
//System.out.println(value);
j++;
}
for (int k = n;k < slashNo; k++ ) {
sizeS = sizeS + charArray[k];
//System.out.println(sizeS);
}
for (int l = slashNo + 1; l < j; l++ ) {
qtyS = qtyS + charArray[l];
//System.out.println(qtyS);
}
resSize[no] = sizeS;
System.out.println(resSize[no]);
resQty[no] = qtyS;
System.out.println(resQty[no]);
System.out.println("Size is: " + resSize[no] + ", and Qty is: " + resQty[no]);
no++;
slashNo = 0;
sizeS = "";
qtyS = "";
}
String fileOutput = JOptionPane.showInputDialog("Enter Output File Name: ") + ".txt";
try{
FileWriter fw = new FileWriter(fileOutput);
PrintWriter pw = new PrintWriter(fw);
String outputSize = null;
String outputQty = null;
for (int t = 1; t < no; t++) {
outputSize = resSize[t];
outputQty = resQty[t];
pw.println(outputSize + " = " + outputQty);
System.out.println("Writing: "+ outputSize + " = " + outputQty);
}
pw.flush();
pw.close();
fw.close();
fr.close();
br.close();
}catch(Exception ex){
System.out.println("Output " + ex);
}
}catch(Exception ex){
System.out.println(ex);
}
}
}
Now its in Generic form but will improve it later. But still its working fine. Thanks for your Help stack overflow Community.

My array Printing NULL

In the method, i have all these initialize
Scanner input = new Scanner(System.in);
File file = new File("order.dat");
File viewOrder = new File("ViewOrder.dat");
String orderNo, itemNo, itemNameHolder, qtyHolder, priceHolder, status;
int hold, count = 0, countArray = 0;
double tempPriceHolder, totalPrice = 0;
String tempStatus = "";
String[] holdItemNo = null;
String[] holdName = null;
Integer[] holdQty = null;
Double[] holdTotal = null;
String[] holdStatus = null;
After, i try to read all my content in the file and store the content into holdX array
try {
BufferedReader br = new BufferedReader(new InputStreamReader(new FileInputStream(file)));
String line = null;
while ((line = br.readLine()) != null) {
String tokens[] = line.split(";");
orderNo = tokens[0];
itemNo = tokens[1];
itemNameHolder = tokens[2];
qtyHolder = tokens[3];
priceHolder = tokens[4];
status = tokens[5];
if (orderNo.equalsIgnoreCase(userOrderNo)) {
tempPriceHolder = Double.parseDouble(priceHolder);
hold = Integer.parseInt(qtyHolder);
tempPriceHolder = tempPriceHolder * hold;
totalPrice += tempPriceHolder;
countArray++;
holdItemNo = new String[countArray];
holdName = new String[countArray];
holdQty = new Integer[countArray];
holdTotal = new Double[countArray];
holdStatus = new String[countArray];
if (status.matches("s")) {
tempStatus = "Success";
} else if (status.matches("p")) {
tempStatus = "Partially Full";
} else if (status.matches("o")) {
tempStatus = "Out of Stock";
}
holdItemNo[count] = itemNo;
holdName[count] = itemNameHolder;
holdQty[count] = hold;
holdTotal[count] = tempPriceHolder;
holdStatus[count] = tempStatus;
count++;
}
}
} catch (Exception e) {
System.out.println("Error");
}
Final, i write all my array into a new file.
System.out.printf("%s %15s %15s %10s %10s\n", "Item No", "Description", "Quantity", "Total", "Status");
for (int i = 0; i < holdItemNo.length; i++) {
System.out.printf("\n%-11s %-18s %-13s $%-8s %s \n", holdItemNo[i], holdName[i], holdQty[i], holdTotal[i], holdStatus[i]);
}
System.out.println("-----------------------------------------------------------------------");
System.out.printf("%46s %s\n", "$", totalPrice);
System.out.print("Print Order to file Y/N: ");
String choice = input.next();
if (choice.equalsIgnoreCase("y")) {
try {
PrintWriter bw = new PrintWriter(new FileWriter("ViewOrder.dat", true));
for (int i = 0; i < holdItemNo.length; i++) {
bw.write(userOrderNo + ";" + holdItemNo[i] + ";" + holdName[i] + ";" + holdQty[i] + ";" + holdTotal[i] + ";" + holdStatus[i] + "\n");
bw.flush();
}
bw.flush();
bw.close();
System.out.println("Sucessfull!");
} catch (Exception e) {
System.out.println("Error");
}
} else if (choice.equalsIgnoreCase("n")) {
System.out.println("");
}
but the problem is even my code is working but the output is not what i expected. It printed out the printed out the last content and also the sub price is working as well but the rest is only printed out NULL.
Example
Also, it gave me warning of Derefencing possible null pointer on the array.length
for (int i = 0; i < holdItemNo.length; i++) {
bw.write(userOrderNo + ";" + holdItemNo[i] + ";" + holdName[i] + ";" + holdQty[i] + ";" + holdTotal[i] + ";" + holdStatus[i] + "\n");
bw.flush();
}
Guessing:
holdItemNo = new String[countArray];
and the following lines: you are creating these new array objects within your reading loop (inside a condition).
So probably that condition never goes true; therefore your arrays stay all null. But even when the condition is met - you probably expect that to happen more then once. And guess what: you are creating completely new arrays then. While throwing away the previously created array. Each time the if condition turns true you will lose previously stored values!
So the answer is: create your arrays before entering the loop. This means that you either have to query "how many slots to create" upfront; or you have to create an array with say 100 empty slots; and within your loop you then have to check if you still have free slots.
Or you start using java.util.List resp. ArrayList - which allows for dynamic adding of elements.

how to change the color of text partially in android

I have a sentence that contains message to be posted to the server like wow! superb pic #superb #pic #111 #222 enjoyed the pic
I want to extract the hastags and make them colored and leaving the rest of the text intact.
I tried the following code but not working.
private void spannableOperationOnHastag() {
mPostMessage = edPostMessage.getText().toString().trim();
String strPreHash = null;
String strHashText = "";
if (mPostMessage.contains("#")) {
try {
int index = mPostMessage.indexOf("#");
strPreHash = mPostMessage.substring(0, index);
SpannableString spannableString = new SpannableString(strPreHash);
String strHashDummy=mPostMessage.substring(index, mPostMessage.length());
int hashCount= StringUtils.countMatches(strHashDummy, "#"); // check for number of "#" occurrence and run forloop for getting the number of hastags in the string
int hasIndex=0;
for (int i = 0; i <hashCount ; i++) {
strHashText = strHashText+strHashDummy.substring(hasIndex, strHashDummy.indexOf(' '))+" ";
hasIndex =strHashText.indexOf(" "); // updating new space(" ") position in the index variable
}
SpannableString spannableStringBlue = new SpannableString(strHashText);
spannableStringBlue.setSpan(new ForegroundColorSpan(PublishPostActivity.this.getResources().getColor(R.color.blue)), 0, strHashText.length(), Spanned.SPAN_INCLUSIVE_EXCLUSIVE);
edPostMessage.setText(null); // clearing old string
edPostMessage.append(spannableString); // setting extracted coloured text
edPostMessage.append(spannableStringBlue);
} catch (Exception e) {
Log.d(TAG, "validatePostMessage() called with " + "e = [" + e + "]");
}
}
}
I solved the problem my self . I any one needs it can refer this code :)
private void spannableOperationOnHastag() throws Exception{
mPostMessage = edPostMessage.getText().toString()+" "; // extra space for spannable operations
List<Integer> listStartPos = new ArrayList<>();
List<Integer> listEndtPos = new ArrayList<>();
if (mPostMessage.contains("#")){
for (int i = 0; i < mPostMessage.length(); i++) {
if (mPostMessage.charAt(i) == '#') {
listStartPos.add(i);
Log.d(TAG, "startIndex of # = " + i);
}
}
for (int i = 0; i < listStartPos.size(); i++) {
int endIndex = mPostMessage.indexOf(' ', listStartPos.get(i));
listEndtPos.add(endIndex);
Log.d(TAG, "endIndex of # " + (endIndex));
}
SpannableString spanned = SpannableString.valueOf(mPostMessage);
for (int i = 0; i < listStartPos.size(); i++) {
spanned = new SpannableString(spanned);
spanned.setSpan(new ForegroundColorSpan(getResources().getColor(R.color.blue)), listStartPos.get(i), listEndtPos.get(i), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
Log.d(TAG, "substring " + mPostMessage.substring(listStartPos.get(i), listEndtPos.get(i) + 1));
}
mPostMessage.trim(); // removing extra space.
edPostMessage.setText(null);
edPostMessage.setText(spanned);
}
}
I see you've just posted your own answer, but as I'd nearly finished typing this up I thought I'd go ahead and post this anyway :). I typed it just now without an IDE so it may not be perfect.
private static SpannableString convertTextColorsAtChar(char trigger, String inputText) {
SpannableString spannedText = new SpannableString(inputText);
if (!inputText.contains(trigger)) {
return spannedText;
}
ArrayList<int[]> indexArr = getIndexes(trigger, inputText.toCharArray());
for (int[] indexes : indexArr) {
spannedText.setSpan(new ForegroundColorSpan(Color.RED), indexes[0], indexes[1], Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
}
returned spannedText;
}
private static ArrayList<int[]> getIndexes(char trigger, char[] inputText) {
ArrayList<int[]> values = new ArrayList<int[]>();
int firstIndex = -1;
int secondIndex; = -1
for (int i = 0; i < inputText.length; i++) {
if (firstIndex != -1 && inputText[i] == ' ') {
secondIndex = i;
values.add(new int[] { firstIndex, secondIndex });
firstIndex = secondIndex = -1;
}
if (trigger == inputText[i]) {
firstIndex = i;
}
}
return values;
}
You'd then call it with convertTextColorsAtChar('#', editText.getText().toString());
change your code as below
SpannableString spannableStringBlue = new SpannableString(strHashText);
spannableStringBlue.setSpan(new ForegroundColorSpan(new ForegroundColorSpan(Color.BLUE), 0, strHashText.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
edPostMessage.setText(null); // clearing old string
edPostMessage.append(spannableString); // setting extracted coloured text
edPostMessage.append(spannableStringBlue);
SpannableStringBuilder builder = new SpannableStringBuilder();
String yourSentence = "Pic #superb #pic #111 #222 enjoyed the pic";
String [] newSent = yourSentence.split(" ");
for(int count = 0; count < newSent.length; count++){
if(newSent[count].contains("#")){
SpannableString redSpannable= new SpannableString(newSent[count]);
redSpannable.setSpan(new ForegroundColorSpan(Color.RED), 0, newSent[count].length(), Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
Log.v("Test", "color_string" + newSent[count]);
builder.append(redSpannable+" ");
} else{
builder.append(newSent[count]+" ");
Log.v("Test", "normal_string" + newSent[count]);
}
}
holder.PhName.setText(builder, TextView.BufferType.SPANNABLE);

AutoIndent bracket in Java Swing JeditorPane

I am working on a code-editor in java and i want to know how to auto-indent using brackets (open and close) like an actual code editor .
like this 1:
Array PrincipalVar = (Var => (OtherVar => (var3 => 3,
var4 => 8,
var6 => 1)
),
Var2 => (var => 1))
Editor is a JEditorPane. I tried some code, but nothing seem to work.
I have already file contening code, and I want to Re-Indent this file.
Code I already tried :
public String indentFileTry() throws FileNotFoundException{
LinkedList<Integer> inBracket = new LinkedList<Integer>();
String currentLine = "";
Scanner indent = new Scanner(new FileReader(f));
String ptu = "";
while(indent.hasNextLine()) {
currentLine = indent.nextLine();
currentLine = currentLine.trim();
char[] line = currentLine.toCharArray();
int i = 0;
while(i < line.length){ //Here I define the position of the Bracet for Indentation
if(line[i] == '('){
inBracket.addFirst(i);
}
i++;
}
if(!inBracket.isEmpty()){//here I indent with the position of the bracket and I remove the first(First In First Out)
if(!currentLine.contains(")")){
int spaceadded = 0;
String space ="";
while(spaceadded <= inBracket.getFirst()){
spaceadded++; space += " ";
}
currentLine = space + currentLine;
inBracket.removeFirst();
}else if(currentLine.contains(")")){
int spaceadded = 0;
String space ="";
while(spaceadded <= inBracket.getFirst()){
spaceadded++; space += " ";
}
currentLine = space + currentLine;
inBracket.removeFirst();
}
}
ptu += currentLine +"\n";
}
indent.close() ;
System.out.println(ptu);
return ptu;
}
If you expect automatically indentation you won't get such code. You should implement it yourself adding \n spaces (or \t) chars to format your code. JEditorPane does not understand your code logic. You (with your code parser) should define parent/child relation for lines of code you have.
One example for the case when parent/children are defined is XML. See the XMLEditorKit where nodes are indented.
For the response, What I do is easy.
I made a LinkedList, and I use it like a FILO (First in Last out) like this :
public String indentFile() throws FileNotFoundException{
LinkedList<Integer> positionBracket = new LinkedList<Integer>();
String currentLine = "";
Scanner indent = new Scanner(new FileReader(f));
String stringIndented = "";
while(indent.hasNextLine()) {
currentLine = indent.nextLine();
currentLine = currentLine.trim();
char[] lineInChar = currentLine.toCharArray();
int i = 0;
int spaceadded = 0;
String space ="";
if(!positionBracket.isEmpty()){
while(spaceadded <= positionBracket.getFirst()){
spaceadded++;
space += " "; // We put same space like the last opened bracket
}
}
while(i < lineInChar.length){
if(lineInChar[i] == '('){ //If opened bracket I put the position in the top of the Filo
positionBracket.addFirst(new Integer(i));
}
if(lineInChar[i] == ')' && !countCom){
positionBracket.removeFirst(); //If closed bracket I remove the position on the top of the Filo
}
i++;
}
stringIndented += space + currentLine +"\n";
}
}
return stringIndented;
}

Categories