Jump to content

  • Log In with Google      Sign In   
  • Create Account


Building a calculator in C#, stuck on doing the math stuff.


Old topic!
Guest, the last post of this topic is over 60 days old and at this point you may not reply in this topic. If you wish to continue this conversation start a new topic.

  • You cannot reply to this topic
50 replies to this topic

#21 Oberon_Command   Crossbones+   -  Reputation: 1707

Like
0Likes
Like

Posted 29 June 2012 - 11:21 PM



Like, getting the calculator to add multiple numbers.


So, my attempted summary of the situation.

You have a textbox containing a string which represents the expression to be calculated.
You want to take the equation represented in string in the textbox and compute the output of the expression.
But the string representation of the expression isn't very useful to you - at least, not yet.

Am I correct so far?


yes

I want to have the calculator able to deal with multiple numbers instead of just 2.

97 + 576 + 46, etc.

I originally thought storing each number in an array/list somehow would do the trick, but dealing with taking the numbers out of the string after each math symbol is what has me stuck atm.


Okay.

Just so we're on the same page here: leaving aside the problem of "taking the numbers out of the string" (there's a specific term for this - expression parsing - which we'll get to in a moment), have you determined how to deal with the numbers once they're "out of the string?" If so, can you please post the code so that we can see where you're going with it? If not, let's tackle that problem, first since it's easier - write code that takes each number in an array (or a list, if you prefer - this is what I would prefer, for reasons that will become clear later) and adds them together.

As an aside: I often find it helpful to write a program in chunks according to what I already know how to do. If I know how one particular step works, and I know exactly what sort of thing I'm going to get from the steps before it but not how that predecessor step will work, then I can write that particular step in isolation with some "dummy" test data in the format that I think that particular step will consume once the one before it is done. That's useful for unit testing, as well - if I can verify that each part of my program works on its own when given data that I know should work, then I can track down bugs more easily.

Edited by Oberon_Command, 29 June 2012 - 11:30 PM.


Sponsor:

#22 Bill Fountaine   Members   -  Reputation: 193

Like
0Likes
Like

Posted 29 June 2012 - 11:32 PM

What I had in mind was adding a List of ints. Then whenever the user presses a math button, store the preceding substring of numbers in the list, but right now I'm having trouble cutting the substring of numbers out of the string.

Edited by Bill Fountaine, 29 June 2012 - 11:34 PM.


#23 AdrianC   Members   -  Reputation: 591

Like
0Likes
Like

Posted 29 June 2012 - 11:36 PM

While some people on here are being quite rude, they are right on one thing, being a programmer is not about reading a tutorial, and then knowing how to do that 1 thing. Its about being able to solve problems on your own. Anyway.

This is probably the simplest way to approach the issue, though not necessarily the best:

Your user enters a string along the lines of 10 + 20 - 5. Parse that string and store each number in one array. Also store the symbols in a separate array.

Now you have array A = {10, 20, 5} and B = {"+"," -"} (note this is just pseudocode)

Now parse the two arrays and perform the operations. Pretty basic. If you need an actual example:

while (A.length > 1)
{
  if (B[0] == "+")
  {
	A[1] = A[0] + A[1];
	remove first element of A;
	remove first element of B;
  }
  //add other symbol options here
}

Now A[0] will contain the solution.

Of course for things like multiplication you'll have to take into account order of operations, but I won't solve the whole thing for you.

#24 Oberon_Command   Crossbones+   -  Reputation: 1707

Like
0Likes
Like

Posted 29 June 2012 - 11:39 PM

What I had in mind was adding a List of ints. Then whenever the user presses a math button, store the preceding string of numbers in the list, but right now I'm having trouble cutting the substring of numbers out of the string.


I realize that. You seem very insistent on this. But work with me for a bit - try writing the "adding a list of ints" bit before you write the code that cuts the numbers out of the string. In essence, expand AdrianC's example into actual, working code. Post the code here when you're done.

Edited by Oberon_Command, 29 June 2012 - 11:44 PM.


#25 Bill Fountaine   Members   -  Reputation: 193

Like
0Likes
Like

Posted 30 June 2012 - 12:15 AM

I think I am just going to stop while I'm ahead so I don't make myself look any more incompetent than I already have. Obviously the concept of "program, don't just look at tutorials that teaches you how to use stuff." isn't doing anything for me. If I could find something similar to http://www.cplusplus.com/forum/articles/12974/ using C#, in terms of setup (working from the ground up, making you do exercises using stuff you've learned, etc). That would be great. The tutorials I have been watching lately, which have me jumping straight into windows forms, are the ones from http://thenewboston.org/list.php?cat=15

Problem solving is easy. I just need to learn the ins and outs of the language to know what syntax I can use to solve said problems.

#26 Oberon_Command   Crossbones+   -  Reputation: 1707

Like
0Likes
Like

Posted 30 June 2012 - 12:42 AM

I think I am just going to stop while I'm ahead so I don't make myself look any more incompetent than I already have.


I must say, your attitude seems very defeatist.

Obviously the concept of "program, don't just look at tutorials that teaches you how to use stuff." isn't doing anything for me.


But that's what programming is. You'll never learn if you don't think for yourself.

I reiterate - post the exact sequence of steps that you want to do and we'll help you find the syntax to carry them out. If you know what you want to do and it's only the syntax that escapes you, then you should have no trouble doing this. If you're having trouble doing that, then clearly it is not just the syntax you're really having trouble with. What little you've told us is not enough - you're on the right track, but you need to break the problem down further before you get to the level where syntax matters. With that said, I'm going to give you a hint you may find useful in the form of some sample code.

// starting expression
string expr = "1 + 2";

// see http://msdn.microsoft.com/en-us/library/b873y76a.aspx for documentation on precisely how Split() works
string[] tokens = expr.Split(' ');

// exercise: what will get printed to the screen?
foreach (string t in tokens)
	System.Console.WriteLine(t);

The tutorials I have been watching lately, which have me jumping straight into windows forms, are the ones from http://thenewboston....list.php?cat=15


Which of those tutorials have you watched?

Problem solving is easy. I just need to learn the ins and outs of the language to know what syntax I can use to solve said problems.


You will find as you program more and more complicated things that the syntax is actually the easy part, and the problem solving the hard part.

Edited by Oberon_Command, 30 June 2012 - 12:51 AM.


#27 Nypyren   Crossbones+   -  Reputation: 3414

Like
0Likes
Like

Posted 30 June 2012 - 12:47 AM

TextBox.Text
int.TryParse
MessageBox.Show

Google each of them for examples. Try the examples out in your code. Watch what they do.


Here is your quiz:

string s = ???;  // get it from your textbox.
int value;
???; // replace the ??? to convert the string to an integer.  Show a messagebox with an error if it fails.
value = value * 5;
// put the resulting value back in the textbox.

Edited by Nypyren, 30 June 2012 - 12:50 AM.


#28 Bill Fountaine   Members   -  Reputation: 193

Like
-1Likes
Like

Posted 30 June 2012 - 12:55 AM


I think I am just going to stop while I'm ahead so I don't make myself look any more incompetent than I already have.


I must say, your attitude seems very defeatist.

Obviously the concept of "program, don't just look at tutorials that teaches you how to use stuff." isn't doing anything for me.


But that's what programming is. You'll never learn if you don't think for yourself.

I reiterate - post the exact sequence of steps that you want to do and we'll help you find the syntax to carry them out. If you know what you want to do and it's only the syntax that escapes you, then you should have no trouble doing this. If you're having trouble doing that, then clearly it is not just the syntax you're really having trouble with. What little you've told us is not enough - you're on the right track, but you need to break the problem down further before you get to the level where syntax matters. With that said, I'm going to give you a hint you may find useful in the form of some sample code.

// starting expression
string expr = "1 + 2";

// see http://msdn.microsoft.com/en-us/library/b873y76a.aspx for documentation on precisely how Split() works
string[] tokens = expr.Split(' ');

// exercise: what will get printed to the screen?
foreach (string t in tokens)
	System.Console.WriteLine(t);

The tutorials I have been watching lately, which have me jumping straight into windows forms, are the ones from http://thenewboston....list.php?cat=15


Which of those tutorials have you watched?

Problem solving is easy. I just need to learn the ins and outs of the language to know what syntax I can use to solve said problems.


You will find as you program more and more complicated things that the syntax is actually the easy part, and the problem solving the hard part.


I've watched up to vid 18, but I know about some of the other stuff in the other videos.

As for the code itself, I'll get back to that in a bit. I need to get some coffee in me and wake up fully first.

#29 Bill Fountaine   Members   -  Reputation: 193

Like
0Likes
Like

Posted 30 June 2012 - 03:00 AM

The exact steps I want to do:

Once the user presses a math operator button, store the string of numbers prior to that in an array.
Do math with contents from array
Hit equals button to display result

#30 DevLiquidKnight   Members   -  Reputation: 829

Like
0Likes
Like

Posted 30 June 2012 - 03:04 AM

If your not acquainted with the idea of reading books on the subject of C# such as in this case. I recommend you start, it would give you exactly what you want if you can find the right book. Examples along with "problem sets" that you can solve to further your skills which is what it sounds like your looking for. Such as Head First C#, 2E: A Learner's Guide to Real-World Programming with Visual C# and .NET


Links that might help:
http://www.c-sharpcorner.com/Beginners/
http://www.homeandlearn.co.uk/csharp/csharp.html
http://www.fincher.org/tips/Languages/csharp.shtml

#31 Bill Fountaine   Members   -  Reputation: 193

Like
-1Likes
Like

Posted 30 June 2012 - 03:14 AM

If your not acquainted with the idea of reading books on the subject of C# such as in this case. I recommend you start, it would give you exactly what you want if you can find the right book. Examples along with "problem sets" that you can solve to further your skills which is what it sounds like your looking for. Such as Head First C#, 2E: A Learner's Guide to Real-World Programming with Visual C# and .NET


Links that might help:
http://www.c-sharpco....com/Beginners/
http://www.homeandle...arp/csharp.html
http://www.fincher.o...es/csharp.shtml


but I have stated I have a million books on the subject..including the one you provided. I will go through the tutorials on the sites you provided. I know about csharpcorner but never really did the stuff on it.

#32 jeyanthinath   Members   -  Reputation: 111

Like
0Likes
Like

Posted 30 June 2012 - 04:06 AM

hai just get the total thing as a string and and then trim the thing using the operators like (+,-,*,/) and store the variable proceeding it in a array and do your calculation

#33 Xanather   Members   -  Reputation: 701

Like
0Likes
Like

Posted 30 June 2012 - 04:12 AM

I made this just for u Posted Image

[source lang="csharp"]using System;using System.Collections.Generic;namespace TestAppForGameDev{ class Program { static List<Calculation> calculation = new List<Calculation>(); static void Main(string[] args) { Console.Write("Set a inital value to multiply/add/minus/divide from: "); string inital_string = Console.ReadLine(); double initalvalue = double.Parse(inital_string); string calculationappearance = inital_string; Console.WriteLine("Add more values using /add, /minus, /divide or /multiply."); Console.WriteLine("Use /calc to calculate the answer!"); while (true) { string input_string = Console.ReadLine(); string[] input_string_split = input_string.Split(' '); //separate the type of cmd to the specified cmd data, string[] is a array. if (input_string_split[0] == "/add") { calculation.Add(new Calculation(double.Parse(input_string_split[1]), Calculation.Type.Add)); calculationappearance += " + " + input_string_split[1]; } else if (input_string_split[0] == "/minus") { calculation.Add(new Calculation(double.Parse(input_string_split[1]), Calculation.Type.Minus)); calculationappearance += " - " + input_string_split[1]; } else if (input_string_split[0] == "/divide") { calculation.Add(new Calculation(double.Parse(input_string_split[1]), Calculation.Type.Divide)); calculationappearance += " / " + input_string_split[1]; } else if (input_string_split[0] == "/multiply") { calculation.Add(new Calculation(double.Parse(input_string_split[1]), Calculation.Type.Multiply)); calculationappearance += " * " + input_string_split[1]; } else if (input_string_split[0] == "/calc" || input_string_split[0] == "/calculate") { Console.WriteLine("Calculating " + calculationappearance); double result = initalvalue; for (int i = 0; i < calculation.Count; i++) { switch (calculation[i].type) { case Calculation.Type.Add: result += calculation[i].value; break; case Calculation.Type.Minus: result -= calculation[i].value; break; case Calculation.Type.Multiply: result *= calculation[i].value; break; case Calculation.Type.Divide: result /= calculation[i].value; break; } } Console.WriteLine("Result: " + result.ToString()); Console.ReadLine(); //make sure user can see result break; //get out of the while loop and close the program } } } } class Calculation { public enum Type { Add, Minus, Divide, Multiply } public double value; public Type type; public Calculation(double value, Type type) { this.value = value; this.type = type; } }}[/source]
Mess around with it, change things around, look up what the List is that is in the source here on MSDN, look up enums too, there are code examples everywhere on there. I hope i helped...

Edited by Xanather, 30 June 2012 - 08:13 AM.


#34 Bill Fountaine   Members   -  Reputation: 193

Like
0Likes
Like

Posted 30 June 2012 - 05:48 AM

I did a little searching around, and ended up finding exactly what I was looking for in terms of code to learn from.

[source lang="csharp"]using System;using System.Collections.Generic;using System.ComponentModel;using System.Data;using System.Drawing;using System.Linq;using System.Text;using System.Windows.Forms;namespace Calculator{ public partial class Form1 : Form { public Form1() { InitializeComponent(); } string sOperator = ""; string sFirstValue = ""; private void button0_Click(object sender, EventArgs e) { textBox1.Text += button0.Text; } private void button1_Click(object sender, EventArgs e) { textBox1.Text += button1.Text; } private void button2_Click(object sender, EventArgs e) { textBox1.Text += button2.Text; } private void button3_Click(object sender, EventArgs e) { textBox1.Text += button3.Text; } private void button4_Click(object sender, EventArgs e) { textBox1.Text += button4.Text; } private void button5_Click(object sender, EventArgs e) { textBox1.Text += button5.Text; } private void button6_Click(object sender, EventArgs e) { textBox1.Text += button6.Text; } private void button7_Click(object sender, EventArgs e) { textBox1.Text += button7.Text; } private void button8_Click(object sender, EventArgs e) { textBox1.Text += button8.Text; } private void button9_Click(object sender, EventArgs e) { textBox1.Text += button9.Text; } private void buttonAdd_Click(object sender, EventArgs e) { sFirstValue = textBox1.Text; textBox1.Text = String.Empty; sOperator = buttonAdd.Text; } private void buttonSubtract_Click(object sender, EventArgs e) { sFirstValue = textBox1.Text; textBox1.Text = String.Empty; sOperator = buttonSubtract.Text; } private void buttonMultiply_Click(object sender, EventArgs e) { sFirstValue = textBox1.Text; textBox1.Text = String.Empty; sOperator = buttonMultiply.Text; } private void buttonDivide_Click(object sender, EventArgs e) { sFirstValue = textBox1.Text; textBox1.Text = String.Empty; sOperator = buttonDivide.Text; } private void buttonEquals_Click(object sender, EventArgs e) { float result = 0; switch (sOperator) { case "+": result = float.Parse(sFirstValue) + float.Parse(textBox1.Text); break; case "-": result = float.Parse(sFirstValue) - float.Parse(textBox1.Text); break; case "*": result = float.Parse(sFirstValue) * float.Parse(textBox1.Text); break; case "/": result = float.Parse(sFirstValue) / float.Parse(textBox1.Text); break; } textBox1.Text = String.Empty; textBox1.Text = Convert.ToString(result); } private void buttonClear_Click(object sender, EventArgs e) { textBox1.Text = String.Empty; } }}[/source]

Edit: I take it back, the code doesn't do what I'm looking for, I thought it did. It only does it after you hit =. Otherwise, you can only add two numbers.

Edited by Bill Fountaine, 30 June 2012 - 05:51 AM.


#35 Telastyn   Crossbones+   -  Reputation: 3692

Like
2Likes
Like

Posted 30 June 2012 - 06:40 AM

Copying code out of google and books is not programming.

#36 Bill Fountaine   Members   -  Reputation: 193

Like
0Likes
Like

Posted 30 June 2012 - 06:53 AM

Copying code out of google and books is not programming.


I know this....

God forbid someone doesn't know how to do something and goes looking to get an idea.

#37 rip-off   Moderators   -  Reputation: 6873

Like
1Likes
Like

Posted 30 June 2012 - 06:57 AM

Your confusing two distinct issues. There is the programs user interface, and its internal implementation. You are focussing on the user interface, and this is causing the internal implementation to become more complex.

You do not need to parse strings to do this. The strings could instead be inferred from some program state (in a more convenient format for computation).

Let us think about the operations you are exposing, while ignoring the interface. The user can use the 10 digits, and the 4 standard operators. Finally, there is a way to evaluate this. Let us design this system in English.

If we ignore operator precedence, we can model this simply as two lists - a list of numbers and a list of operators. There must always be at least as many numbers as operators, but there can be one more. We use a state machine to determine what should happen if the user presses a button.

If the user presses a digit:
  • If there as many operators as numbers, then append this digit to the numbers list.
  • If there are more numbers than operators, if the user presses a digit then multiple the last number by ten and add the digit.
You should eventually handle overflow, but this will suffice for the moment.

If the user presses an operator:
  • If there are less operators than numbers, then append the operator the user pressed.
  • If there as many operators as numbers then replace the last operator with the one the user wants.

If the user tries to evaluate:
  • If the lists are empty, then display an error (or do nothing).
  • If there are as many operators as numbers, then display an error (we need a final number to match the last operator).
  • If there are less operators than numbers, then iterate over both lists, using an accumulator set from the first number, and applying each operator to the accumulator and operator in turn.

Psuedo-code for this might look like;
enumeration Operator {
    Plus, Minus, Multiply, Divide
}

type Calculator {

    function digit(number x)

    function operator(Operator operator)

    function evaluate() -> number or Error
}

There is one missing piece - and that is allowing the U.I. to present the current state of the program. We can provide a function which will built a string representation of the expression string. You'll need to figure out how to translate this into a C# class. The key point is that the user interface is now decoupled from the internal representation.

You don't need to parse current string - the string is a textual representation of the program's state. By storing the program's state as a string, you are actually throwing away information that you knew as the string was being built.

#38 Bill Fountaine   Members   -  Reputation: 193

Like
-2Likes
Like

Posted 30 June 2012 - 07:49 AM

Ok, after thinking over a little bit, I think I at least have the ball rolling. I managed to figure out a way to store the numbers without the math signs. I don't have any of the adding/subtracting/multiplying/dividing logic in yet. Still gotta figure that one out:

[source lang="csharp"]using System;using System.Collections.Generic;using System.ComponentModel;using System.Data;using System.Drawing;using System.Linq;using System.Text;using System.Windows.Forms;namespace Calculator{ public partial class Form1 : Form { public Form1() { InitializeComponent(); } List<string> numbers = new List<string>(); string currentString = ""; char[] mathSymbols = { '+', '-', '*', '/',' '}; private Boolean lastCharIsSymbol { get; set; } bool add = false; bool subtract = false; bool multiply = false; bool divide = false; private void button0_Click(object sender, EventArgs e) { textBox1.Text += button0.Text; lastCharIsSymbol = false; } private void button1_Click(object sender, EventArgs e) { textBox1.Text += button1.Text; lastCharIsSymbol = false; } private void button2_Click(object sender, EventArgs e) { textBox1.Text += button2.Text; lastCharIsSymbol = false; } private void button3_Click(object sender, EventArgs e) { textBox1.Text += button3.Text; lastCharIsSymbol = false; } private void button4_Click(object sender, EventArgs e) { textBox1.Text += button4.Text; lastCharIsSymbol = false; } private void button5_Click(object sender, EventArgs e) { textBox1.Text += button5.Text; lastCharIsSymbol = false; } private void button6_Click(object sender, EventArgs e) { textBox1.Text += button6.Text; lastCharIsSymbol = false; } private void button7_Click(object sender, EventArgs e) { textBox1.Text += button7.Text; lastCharIsSymbol = false; } private void button8_Click(object sender, EventArgs e) { textBox1.Text += button8.Text; lastCharIsSymbol = false; } private void button9_Click(object sender, EventArgs e) { textBox1.Text += button9.Text; lastCharIsSymbol = false; } private void buttonAdd_Click(object sender, EventArgs e) { if (textBox1.Text == "" || lastCharIsSymbol) return; else { textBox1.Text += buttonAdd.Text; currentString = textBox1.Text; currentString.TrimEnd(mathSymbols); numbers.Add(currentString); lastCharIsSymbol = true; add = true; } } private void buttonSubtract_Click(object sender, EventArgs e) { if (textBox1.Text == "" || lastCharIsSymbol) return; else { textBox1.Text += buttonSubtract.Text; currentString = textBox1.Text; currentString.TrimEnd(mathSymbols); numbers.Add(currentString); lastCharIsSymbol = true; subtract = true; } } private void buttonMultiply_Click(object sender, EventArgs e) { if (textBox1.Text == "" || lastCharIsSymbol) return; else { textBox1.Text += buttonMultiply.Text; currentString = textBox1.Text; currentString.TrimEnd(mathSymbols); numbers.Add(currentString); lastCharIsSymbol = true; multiply = true; } } private void buttonDivide_Click(object sender, EventArgs e) { if (textBox1.Text == "" || lastCharIsSymbol) return; else { textBox1.Text += buttonDivide.Text; currentString = textBox1.Text; currentString.TrimEnd(mathSymbols); numbers.Add(currentString); lastCharIsSymbol = true; divide = true; } } private void buttonClear_Click(object sender, EventArgs e) { textBox1.Text = String.Empty; } private void buttonEquals_Click(object sender, EventArgs e) { if (add) { } if (subtract) { } if (multiply) { } if (divide) { } } }}[/source]

basically, I created a char array, involving the math symbols + whitespace; I trim that off the end, and then store that value into the List.

One thing occured to me just as I thought I got this. This isn't going to just keep adding on the numbers that were already in the textbox, to a new list slot will it?

For example, say you put 25 as the first number, that gets stored, then you hit + or w/e and put 86.

First list slot: 25
Second list slot: This won't be 2586 will it? Thats what concerns me.

EDIT: Close topic please, I can already see that this is going to be dead wrong. So I give up

Edited by Bill Fountaine, 30 June 2012 - 08:27 AM.


#39 Oberon_Command   Crossbones+   -  Reputation: 1707

Like
0Likes
Like

Posted 30 June 2012 - 09:06 AM

First list slot: 25
Second list slot: This won't be 2586 will it? Thats what concerns me.


With the way you have it right now, it almost will, but it won't. Let's look at the code to see why. Here's a snippet from the code you just posted.


   if (textBox1.Text == "" || lastCharIsSymbol)
				return;
			else
			{
				textBox1.Text += buttonMultiply.Text;
				currentString = textBox1.Text;
				currentString.TrimEnd(mathSymbols);
				numbers.Add(currentString);
				lastCharIsSymbol = true;
				multiply = true;
			}


Firstly, String.TrimEnd() doesn't actually modify the string. It returns a copy of the string with whatever characters are in mathSymbols trimmed off. This is because in C#, strings are immutable. Practically speaking, this means that once a string object has a value, you CANNOT change it without creating a new string, so whenever you call a string method you want to take the return value of that method and use that instead of the original string object. Because of this, with the code you have now, you're actually adding the entire contents of the textbox, including the math symbols, to the number list! So let's change that TrimEnd() call to this:


currentString = textBox1.Text.TrimEnd(mathSymbols);


Secondly, TrimEnd() will get you what you want, almost. You're correct in observing that with things the way it is right now, if you have "25 + 86", you'll get "2586," which is close but isn't quite what you want. This actually has a pretty easily solution - don't trim whitespace! Consider that because you've included ' 'in your list of "math symbols", all the spaces between the numbers will get trimmed. So let's stop doing that by changing our definition of mathSymbols to this:


char[] mathSymbols = { '+', '-', '*', '/'};


In actual fact, this array better matches its name - it's a list of math symbols, not a list of math symbols and the space character.

Now when that code is run, currentString should contain "25 86". Now, I've already presented a string method in my last post here that can split up a string into an array of sub-strings...

EDIT: Close topic please, I can already see that this is going to be dead wrong. So I give up


You're doing decently so far. Who cares if it's dead wrong for now? That's how you learn - by making mistakes, learning why they're mistakes, and fixing them. Do you want to learn to program or not? If you can't handle being wrong once in a while, you must have trouble learning anything, never mind programming. I get that this is frustrating you, but if you want to accomplish anything you need to push past the frustration and keep trying.

Edited by Oberon_Command, 30 June 2012 - 09:13 AM.


#40 Bill Fountaine   Members   -  Reputation: 193

Like
0Likes
Like

Posted 30 June 2012 - 09:15 AM

I guess




Old topic!
Guest, the last post of this topic is over 60 days old and at this point you may not reply in this topic. If you wish to continue this conversation start a new topic.



PARTNERS