Trying to decide which programming language I want to learn

Click For Summary
Choosing a programming language to learn can be challenging, especially for someone with a background in older languages like assembly, Fortran, and Pascal. C# and C++ are considered for firmware design, while Python is favored for its ease of use and relevance to gaming, particularly with grandchildren. C++ is noted for its speed and compactness, making it suitable for game programming, but it may require more effort to learn compared to C#. Resources like Visual Studio for C# and various online tutorials can help beginners get started, while microcontroller programming can be explored through platforms like Arduino and Raspberry Pi. Ultimately, the choice should align with personal interests in scientific or gaming applications.
  • #271
yungman said:
Sorry, I need to absolutely confirm:
numArray[5] is an array with 5 elements.
numArray is the address that point to the first element of array numArray[5].
Why do you need to confirm this ? it's exactly what I said, and which you quoted.
yungman said:
Are std::strings like this also?
No, they are very different.
yungman said:
Without brackets is the address pointing to the first element?
No. In @jtbell's post, name is a string instance, an object of type std::string. It contains data members such as size and capacity, as well as the data making up the characters in the string, and provides access to all of the function members that belong to the object. A C-type character array has only the characters in it, and none of the other capabilities of the Standard Template Library string class.
 
Technology news on Phys.org
  • #272
yungman said:
Are std::strings like this also? Without brackets is the address pointing to the first element?
No, as I wrote in post #266.
 
  • #273
yungman said:
numArray is the address that point to the first element of array numArray[5].
Sort of.

There are two types of raw arrays, static and dynamic. This is a static array. The memory is allocated on the stack, which is limited in size. A dynamic array is allocated manually and stored on the heap, which has much more space.

C:
int x[5]; // static array
int * y= new int[5]; // dynamic allocation
...
delete [] y; // must manually delete y

So you can see x and y are both "arrays", but y's type is a pointer/memory address. x and y are used the same way, by accessing their elements by index with the bracket operator.

So what is the bracket operator in this case? It's actually syntactic sugar (simplified syntax) for two operatotions put together: pointer arithmetic and dereferencing.

To understand pointer arithmetic, first understand that pointers store memory addresses to typed values each with specific sizes in bytes (e.g. an int is 4 bytes), but memory itself is addressed byte by byte. That is, say the first byte (8 bits) has address 1, then the next byte has address 2. An int starting at address 1 covers 4 bytes. So address 5 is the address 1 int beyond address 1. So pointer arithmetic means, say y is a pointer to an int starting at address 1, then y+2 is actually y's value + sizeof(int)*2, which is the address 9, 8 bytes (2 ints) passed the first one.

Now the bracket operator used to access elements in the array is actually doing this: y[2] is equivalent to *(y+2). y+2 gives you the address of the third element using pointer arithmetic. Then the * dereferences the result (another overload), which means it grabs those 4 bytes starting at the address of the first byte where the int value is stored and returns it as an int.

So why is x almost a pointer but not truly a pointer?

When you use the bracket operator to access elements, it's treated like a pointer. You can say it decays in that it is implicitly cast to a pointer first. So for x, the bracket operator is more like this: x[2] is *(((int *)x)+2). This is casting x to a pointer to an int, then doing pointer arithmetic, then dereferencing the pointer. So what is the difference between x and a pointer? Mainly it is that sizeof(x) is the size in bytes of the array, which is 5*4, whereas sizeof(y) is the size of a pointer, which is 8 on 64 bit executables or 4 on 32 bit executables.

std::string can't be explained until you've learned about classes. But you can think of it as an object that internally stores and manages a dynamically allocated c-string/char array.
 
Last edited:
  • #274
yungman said:
I just received this book today by Tony Gaddis
https://www.amazon.com/gp/product/0136022537/?tag=pfamazon01-20
This is an actual textbook, written for use in college/university programming courses. The link is to the 6th edition (2009). By the time it came out, I had already stopped teaching C++, so I never used it myself. That it uses std::string is a good sign. Does it also use std::vector?

It's now up to the 10th edition (2019), so it must be a popular textbook used by many schools. It's expensive because of the way the textbook "racket" works. The 8th edition (2013) probably includes some of the significant additions to C++ in the C++11 standard (like std::array and range-based for-loops). It might be worth watching for a cheap copy of that edition or a later one.

First time I bought a used book that is like this, pages wrinkled, pen marked all over the place, all worn out.

That means it was probably actually used by a student for two semesters in a real C++ course. :cool: Maybe two or three students in successive years, depending on when the next edition appeared.

Because it's a textbook, it probably has lots of programming exercises. Hint, hint... :wink:
 
Last edited:
  • Like
Likes Jarvis323
  • #275
jtbell said:
This is an actual textbook, written for use in college/university programming courses. The link is to the 6th edition (2009). By the time it came out, I had already stopped teaching C++, so I never used it myself. That it uses std::string is a good sign. Does it also use std::vector?

It's now up to the 10th edition (2019), so it must be a popular textbook used by many schools. It's expensive because of the way the textbook "racket" works. The 8th edition (2013) probably includes some of the significant additions to C++ in the C++11 standard (like std::array and range-based for-loops). It might be worth watching for a cheap copy of that edition or a later one.
That means it was probably actually used by a student for two semesters in a real C++ course. :cool: Maybe two or three students in successive years, depending on when the next edition appeared.

Because it's a textbook, it probably has lots of programming exercises. Hint, hint... :wink:
I spent more time on the book reading std::string and even some pointers. It is a REALLY REALLY good book. This is the one my grandson used, he even gave me the pdf file. But due to my neck problem, I cannot read on the monitor for long time, besides I want to ruin my own book by writing notes. I bought the used one for cheap, I am printing the book out chapter by chapter to read now.

So far, it's very clear, I think I only have to print the function and one or two chapters more, those condition logical comparison, boolean stuffs and even the looping stuffs are quite easy, I think I got the idea from even the worst book...the first one. It's the structures, naming stuffs that's hard for me. All the instance, class, headers, objects stuffs. The programming is actually not hard as long as I get all the names straight.

I somehow have a mental block of names, so often I ask the person for phone number, I remember the phone number and didn't remember the name!
 
  • Like
Likes Jarvis323
  • #276
I am so stoked reading the GADDIS book, it is so simple. I read the std::string, but I decided to stop and go through what I learn in the last 2 weeks or so. Now I think I have a better feel of the names...

That object is just a self contained module with both data and programs, it just carry out request from the main program with given parameter and return results. It is like a module that the main program call upon to perform a task.

That cout and cin are object that the main program can call to write a stream onto the console or read as stream from the keyboard, that << and >> are streaming operator.

That header files contain a set of object files of particular type of function that the program to call on. Just like cout and cin are object in iostream for streaming. That we #include <iostream> in order to access to cout and cin.

These were all a blur to me before, the first book doesn't explain any of these. When you guys explain, it's really over my head. This book really starting from basic on up. I went through quite a few pages, I think it's worth my while to even have to stop for a few days and catch up with all the holes I missed.

Before, all the names and terms is just like people's names, why you call John? Why your last name is Jones? It's like I just blindly remember the names and it's hard.

I learn a lot on strings also, but I don't even want to talk about it until I back track all the stuffs and revisit again.

I am stoked.
 
  • #277
I am working of cin.get(). I think I got what I want from the program, BUT, it's really not what I want.

I want the program to read in any character from the keyboard, display it and show the ASCII number. Then loop back to ask another character. I want it to exit when I hit ENTER ( ASCII = 10)

I understand for cin, I need to hit the character and then ENTER to get it going or else it will just sit there and wait. cin.get can recognize ENTER as character. BUT, I still have to hit ENTER again before it will exit the loop. this is because I have to put in cin.ignore to prevent the program from reading the ENTER that is in the stream and exit without looping. Is there any way to exit right when I hit ENTER if I choose to exit?

C++:
#include <iostream>
using namespace std;

int main()
{
    int Ascii = 0;
    char userSelection = 'A';
    do
    {
    cout << "hit any key:  ";
    cin.get(userSelection);
    cin.ignore();
    Ascii = userSelection;
    cout << "you hit: " << userSelection << ",   the ASCII is =  " << Ascii << endl;
    } while (userSelection != 10) ;
    return 0;

}

thanks
 
  • #278
Rather than try and fit an answer into what you wrote, I'm going to totally rewrite it for you. In doing this you will see that nearly every line is different. Apart from the difference between this
C:
int main()
{
  // Code here.
and this
C:
int main() {
  // Code here.
, and 2 spaces of indent vs. 4, which are just different style choices, all the other differences are important. Some of them (like
C:
  int ascii = 0;
vs
C:
    int Ascii = 0;
wont stop your code working, but they can make it more vulnerable to mistakes and you should get into the right habits now.

So here we go, you can also see this working at https://repl.it/repls/RealSubduedAtom. This code is missing comments of course, you might like to add them as you work through it.
C:
#include <iostream>
using namespace std;

#define EOL '\n'

int main() {
  int ascii = 0;
  char userSelection = 0;

  while (userSelection != EOL) {
    cout << "type a key and [enter]: ";
    cin.get(userSelection);
    ascii = userSelection;

    if (userSelection == EOL) continue;

    cin.ignore(255, EOL);
    cout << "the first key was: " << userSelection
      << ", the ASCII is " << ascii << endl;
  }
  return 0;
}
 
  • Like
Likes yungman
  • #279
Thanks, that's what I want, but I don't understand.

So ENTER = '\n' ? I did not know about this!

I don't remember whether I can use const char EOL = '\n' instead of #define EOL '\n'

What is continue? I don't see in while loop have anything to do with this.
 
  • #280
yungman said:
What is continue? I don't see in while loop have anything to do with this.
There are two ways to interrupt a cycle of a loop in the middle:
  • break; exits the loop immediately. The next statement executed is the first statement after the loop's closing-brace.
  • continue; jumps back to the beginning of the loop. In a while loop, the loop condition is tested again, then the loop continues or exits accordingly.
Are you sure it's not in your (Gaddis's) book? Have you tried the index at the end of the book? (I don't have it, so I can't check it for myself.)
 
  • Like
Likes yungman
  • #281
pbuk said:
if (userSelection == EOL) continue;
Wouldn't break instead of continue also exit the loop cleanly in your example?
 
  • Like
Likes pbuk and yungman
  • #282
You put the user's input in two variables, a char and an int, so you could display it in both formats. Instead, you can use just the char variable to get both formats:
Code:
cout << "the first key was: " << userSelection
      << ", the ASCII is " << int(userSelection) << endl;
We call this "casting" the char variable to int.

It works the other way, too. If you have int ascii = 97;, then cout << char(ascii) displays a.
 
  • Like
Likes pbuk
  • #283
pbuk said:
So here we go, you can also see this working at https://repl.it/repls/RealSubduedAtom. This code is missing comments of course, you might like to add them as you work through it.
C:
#include <iostream>
using namespace std;

#define EOL '\n'

int main() {
  int ascii = 0;
  char userSelection = 0;

  while (userSelection != EOL) {
    cout << "type a key and [enter]: ";
    cin.get(userSelection);
    ascii = userSelection;

    if (userSelection == EOL) continue;

    cin.ignore(255, EOL);
    cout << "the first key was: " << userSelection
      << ", the ASCII is " << ascii << endl;
  }
  return 0;
}
Thanks for the program. I think I understand, I just want to confirm one thing.

When cin.get(userSelection), it read two characters into the keyboard buffer: first character and the '\n' as last character. The userSelection contain the first character after the cin.get() line.
Then in the line if (userSelection == EOL), This read out the next character from the keyboard buffer, which is '\n'.

Just want to confirm this.

Thanks
 
  • #284
yungman said:
Thanks for the program. I think I understand, I just want to confirm one thing.

When cin.get(userSelection), it read two characters into the keyboard buffer: first character and the '\n' as last character. The userSelection contain the first character after the cin.get() line.
No, that's not quite right. First of all the code you write does not read into a buffer, this part is done by the operating system. Also, cin is actually a line input buffer cin.get which is why you have to hit enter, rather than a keyboard buffer which reads keys straight away.

So cin.get(userSelection) waits for a character to appear in the keyboard line input buffer (which will only happen after return has been entered) and then reads one character from the buffer into userSelection which is passed by reference.

yungman said:
Then in the line if (userSelection == EOL), This read out the next character from the keyboard buffer, which is '\n'.
Does it look like this code reads anything from any input buffer?
 
  • #285
jtbell said:
Wouldn't break instead of continue also exit the loop cleanly in your example?
Yes it would, but breaking out of a while(true) loop is not a very understandable way to write code. Putting the termination condition up front makes it much easier to see when you want the loop to terminate.

jtbell said:
You put the user's input in two variables, a char and an int, so you could display it in both formats. Instead, you can use just the char variable to get both formats:
Code:
cout << "the first key was: " << userSelection
      << ", the ASCII is " << int(userSelection) << endl;
We call this "casting" the char variable to int.

It works the other way, too. If you have int ascii = 97;, then cout << char(ascii) displays a.
Yes this is the way I would normally do it but the OP used two variables so I kept to that. Note that you can also cast using (int) userSelection which the compiler treats exactly the same way; I prefer this because int(userSelection) looks like a function call. Note also that when you do ascii = userSelection the compiler is performing an implicit cast. With certain compiler settings, userSelection = ascii will report a warning, @yungman can you think why?
 
  • #286
I think I got it.

Thanks
 
  • #287
pbuk said:
So cin.get(userSelection) waits for a character to appear in the keyboard line input buffer (which will only happen after return has been entered) and then reads one character from the buffer into userSelection which is passed by reference.
And of course your cin.ignore() ensures that, if you enter more than one character before pressing 'return', the program processes only the first one and skips over the rest.

A useful exercise for yungman: "comment out" the cin.ignore(), recompile, run, and then enter a word instead of a single character and see what happens.
 
  • Like
Likes yungman
  • #288
I want to know how the keyboard buffer works when using cin, cin.get and cin.ignore.

I still want to confirm about how cin.get can make it jump out of the loop with just hitting ENTER where the rest of the character, you need to enter the character, then press ENTER. Please check what I said is correct or not.

My understanding is when cin >>character, it needs to hit ENTER before it does anything. When hitting ENTER, two characters are stored in the keyboard buffer...the character and '\n'. cin read the first character, leaving the '\n' in the keyboard buffer. If cin.get() follows, it immediate read the '\n' from the last cin and treat it as a character and move on without reading the character supposed to be entered from the keyboard.

I still don't get how C++ pick which character to read in the keyboard buffer, when is it start reading, is it only read when hitting the ENTER key?
 
  • #289
yungman said:
I want to know how the keyboard buffer works when using cin, cin.get and cin.ignore.

I still want to confirm about how cin.get can make it jump out of the loop with just hitting ENTER where the rest of the character, you need to enter the character, then press ENTER. Please check what I said is correct or not.
I am sorry, I can't really understand what you are saying. If you want to work out how it works the best thing is just to play with it.

yungman said:
My understanding is when cin >>character, it needs to hit ENTER before it does anything.
Correct, you won't see anything from cin until you hit enter.
yungman said:
When hitting ENTER, two characters are stored in the keyboard buffer...the character and '\n'.
As many characters as you have typed before hitting enter are in the buffer - it could be 0, 1 or many - as well as the \n (i.e. ENTER) character.

yungman said:
cin read the first character, leaving the '\n' in the keyboard buffer.
Only if it was there - if the first and only character was \n then the buffer is now empty.

yungman said:
If cin.get() follows, it immediate read the '\n' from the last cin and treat it as a character and move on without reading the character supposed to be entered from the keyboard.
Nowhere in either your code or mine is one cin.get() followed by another.

yungman said:
I still don't get how C++ pick which character to read in the keyboard buffer, when is it start reading, is it only read when hitting the ENTER key?
Not exactly. In order for the buffer to be read, two conditions must be satisfied:
  1. the operating system must have stored characters in the buffer; this only happens when you hit ENTER
  2. your code must try to read from the buffer; this only happens when you reach the (compiled) cin.get() statement.
Once both these conditions are satisfied, cin.get() knows that you are looking for a char type so it reads exactly one byte from the buffer. If you have only typed \n, that is what you will get and the buffer will be empty so if you immediately try to flush it your program will wait around for another character to flush. That's why I checked straight away to see if ENTER was the character received from the buffer.
 
  • #290
Somewhere near the beginning of this thread I think I recommended codecademy. I think the way codecademy leads you through exercises would be useful. Please give it a try.
 
  • Like
Likes FactChecker
  • #291
jtbell said:
And of course your cin.ignore() ensures that, if you enter more than one character before pressing 'return', the program processes only the first one and skips over the rest.

A useful exercise for yungman: "comment out" the cin.ignore(), recompile, run, and then enter a word instead of a single character and see what happens.
Yes, I wrote a program with words reading in last name and first, then print out, then as to hit ENTER to quit or any other character to do it again:
C++:
// enter multiple data in one cin
#include <iostream>
using namespace std;

int main()
{
    char LastName[21] = { '\n' }, FirstName[21] = { '\n' };
    char userSelection = 'A';
    do
    {
    cout << endl;
    cout << "Enter LastName and FirstName with a space in between, then hit ENTER "<< "\n";
    cin >> LastName >> FirstName;
    cout << "\n";
    cout << "You entered  " << LastName << " " << FirstName << endl;
    cout << "\n";
    cin.ignore(255, '\n');// clear ENTER
    cout << " Hit any character to repeat, hit ENTER to quit ";
    cout << endl;
    cin.get(userSelection);
    } while (userSelection != '\n');
    return 0;
}
 
  • #292
It seems that in order to do exactly what you want (read a newline character from an input stream, just like any other char), C++ would have to allow for "unbuffered input streams." And C++ simply doesn't provide this capability. All I/O is via abstract streams, which could be connected to your keyboard and display, or to files, or to network sockets...

At least that's how I interpret the following discussion that I found with a Google search for "c++ unbuffered console input":

https://www.daniweb.com/programming...reads/451301/why-no-standard-unbuffered-input

I think I remember reading similar things elsewhere years ago when I was more involved in C++ by teaching it.

There's at least one way to accomplish your ultimate goal, which is to allow the user to terminate an input loop by simply pressing <return>. You don't read to a single char, but to an std::string. And insted of using cin >>, you use the std::getline() function, which reads from an input stream (e.g. cin) until it encounters a newline. The chars up to (but not including) the newline go into the string, and the newline is discarded. To test whether the user simply pressed <return>, you test the string to see if it's empty.

Code:
#include <iostream>
#include <string>

int main ()
{
    std::string choice = "go";
    while (choice != "")
    {
        std::cout << "Enter a character, or <return> to exit: ";
        std::getline (std::cin, choice);
        std::cout << "You entered '" << choice << "'." << std::endl;
        if (choice != "")
        {
            std::cout << "'" << choice[0] << "'" 
              << " has the ASCII code " << int(choice[0]) << "." 
              << std::endl;
        }
    }
    return 0;
}

If the user enters more than one char before pressing <return>, this program displays all of them, but displays the ASCII code for only the first one. Exercise: modify the program so it displays the ASCII codes for all the chars that the user enters.
 
  • Like
Likes Vanadium 50
  • #293
jtbell said:
It seems that in order to do exactly what you want (read a newline character from an input stream, just like any other char), C++ would have to allow for "unbuffered input streams." And C++ simply doesn't provide this capability. All I/O is via abstract streams, which could be connected to your keyboard and display, or to files, or to network sockets...
No, there is no problem with reading a newline character from an input stream as you can see from my code in #278(!). The problem with @yungman's code was that after reading one character (which could be a newline) he was calling ignore() which was waiting around for another newline.

jtbell said:
There's at least one way to accomplish your ultimate goal, which is to allow the user to terminate an input loop by simply pressing <return>. You don't read to a single char, but to an std::string. And insted of using cin >>, you use the std::getline() function, which reads from an input stream (e.g. cin) until it encounters a newline. The chars up to (but not including) the newline go into the string, and the newline is discarded. To test whether the user simply pressed <return>, you test the string to see if it's empty.
Yes, std::getline() is generally more useful than cin >>. But actually neither of these are very useful - interactive console programs aren't really a thing in C++; if I were @yungman I'd drop it and move on.
 
  • #294
I run into problem building the solution. I got an error message
C++:
// Read and write to file
#include<iostream>
#include<fstream>
using namespace std;

int main()
{
    ofstream outputFile;
    outputFile.open("demofile.txt");
    cout << "Now writing data to the demofile.txt" << endl;
    outputFile << "Bach\n";
    outputFile << "Beethoven\n";
    outputFile << "Mozart\n";
    outputFile << "Schubert\n";

    outputFile.close();
    cout << "Done " << endl;
    cout << endl;
    return 0;

}
Compile error file write.jpg


I triple checked, I type everything right straight out from the book. Please help

Thanks
 
Last edited:
  • #295
The error message says that your path name length plus the generated file name length exceeds the 250 character limit. You can reduce the length by reducing the number or lengths of the concatenated components. For example, the generated file name includes your project name, so using a shorter project name would contribute to staying within the limit.

https://stackoverflow.com/questions...-file-the-spcified-path-filename-are-too-long
 
  • Like
Likes yungman
  • #296
sysprog said:
The error message says that your path name length plus the generated file name length exceeds the 250 character limit. You can reduce the length by reducing the number or lengths of the concatenated components. For example, the generated file name includes your project name, so using a shorter project name would contribute to staying within the limit.

https://stackoverflow.com/questions...-file-the-spcified-path-filename-are-too-long
I don't understand, it is a new file as you see created by the program named "demofile.txt". It only contain 4 words( 4 names). It is less than 50 characters if you count them all including the name of the file.

thanks

EDIT: I went in and deleted 3 out of 4 names, still fail.
 
Last edited:
  • #297
yungman said:
I don't understand, it is a new file as you see created by the program named "demofile.txt". It only contain 4 words( 4 names). It is less than 50 characters if you count them all including the name of the file.

thanks
Please look at the file name in the error message ##-## it's between quotation marks, and it's about 100 characters long. The file name that the message is reporting is the VS-generated name of a debug file. The fully-qualified name includes the path name, which includes everything in the directory structure from the drive letter to the most deeply nested current subdirectory. It also includes the whole of your project name, which lengthily describes the program, instead of just being something like P002. You can also rename directories to something shorter, e.g. abbreviate Microsoft to MS, and Visual Studio to VS. The full path character string from drive letter to current subdirectory doesn't appear in the message, so I can't see all the reductions you could do to reduce its length.
 
  • Like
Likes yungman
  • #298
sysprog said:
Please look at the file name in the error message it's between quotation marks, and it's about 100 characters long.
I think I copied it correctly here:

Debug\3.29 rea.63bf1643e.tlog\3.29 read write to file ifstream ofstream open close.lastbuildstate

The full path name is probably much longer, as sysprog described.

I suspect that "3.29 read write to file ifstream ofstream open close" is the name that yungman chose for the project or something related to it. It looks like an exercise number (3.29) followed by keywords describing the program to help him find it later. "lastbuildstate" looks like it might be a suffix generated by Visual Studio for internal purposes.

I suggest that he go to wherever he entered that name, and replace it with a much shorter one, maybe something like "3.29 fstream".

I'm just guessing here, because I've never used Visual Studio.

I copied and pasted the program as shown, into a .cpp file on my iMac. My compiler (g++) compiles it successfully, and it produces the expected output.
 
  • Like
Likes yungman and sysprog
  • #299
jtbell said:
Debug\3.29 rea.63bf1643e.tlog\3.29 read write to file ifstream ofstream open close.lastbuildstate

The full path name is probably much longer, as sysprog described.
jtbell said:
I'm just guessing here, because I've never used Visual Studio.
I agree with @jtbell and @sysprog that the filename of the source code is the problem.
I copied the program verbatim and ran it through VS, and it worked as expected.
 
  • Like
Likes sysprog
  • #300
I solved the problem. It is the name of my whole project I created! I tried to make it more descriptive on the name so in the future when I read the name, I can know what the program does. This is old age for you, can't remember after a while. 3.29 doesn't mean anything to me later on. I did a lot of exercise with the first book and I don't remember what they are until I open them. So for the Gaddi's book I give descriptions...AND it's too long!

Now, I deleted the whole project, saving only the source.cpp. Create a new project called 3.29 ofstream and it compiled.

VS has strange things, I found the demofile.txt that created by the program now. Also VS is strange, I before I end up deleting the whole project, I tried to change the name of EVERY file inside, it's like every time I navigate around, I see new names that I missed the first time! It just did not work trying to rename the files, finally, I had to take out the source.cpp, then try to delete. Then I had to close all the other projects ( I had the ifstream project opened in another VS program) in order to even create the new 3.29 ofstream.

Now my other ifstream doesn't read the demofile.txt. That's another story for another day. I want to work on that first.
 
Last edited:
  • Like
Likes jtbell

Similar threads

  • · Replies 15 ·
Replies
15
Views
3K
  • · Replies 107 ·
4
Replies
107
Views
9K
  • · Replies 8 ·
Replies
8
Views
2K
Replies
16
Views
3K
  • · Replies 54 ·
2
Replies
54
Views
5K
  • · Replies 11 ·
Replies
11
Views
2K
  • · Replies 13 ·
Replies
13
Views
2K
  • · Replies 9 ·
Replies
9
Views
2K
  • · Replies 16 ·
Replies
16
Views
2K
  • · Replies 58 ·
2
Replies
58
Views
4K