Archived

This topic is now archived and is closed to further replies.

EGD Eric

Unresolved external symbols?

Recommended Posts

I copied this code exactly from the book, but I get unresolved external symbols. Its supposed to display a rotating red triangle on the screen. Can someone please copy/paste this into their compiler and tell me what you think? #define WIN32_LEAN_AND_MEAN #include <windows.h> #include <gl/gl.h> //Standard OpenGL include #include <gl/glu.h>//OpenGL utilities #include <gl/glaux.h> //OpenGL auxiliary functions //Global Variables float angle = 0.0f; //Current angle of the rotating triangle HDC g_HDC; //global device context //Function to set the pixel format for the device void SetupPixelFormat(HDC hDC) { int nPixelFormat; //your pixel format index static PIXELFORMATDESCRIPTOR pfd = { sizeof(PIXELFORMATDESCRIPTOR), //Size of the structure 1, //Version, always set to 1 PFD_DRAW_TO_WINDOW | //support window PFD_SUPPORT_OPENGL | //support openGL PFD_DOUBLEBUFFER, //support double buffering PFD_TYPE_RGBA, //RGBA color mode 32, //go for 32 bit color mode 0, 0, 0, 0, 0, 0, //Ignore color bits, not used 0, //No alpha buffer 0, //Ignore shift bit 0, //No accumulation buffer 0, 0, 0, 0, //Ignore accumulation bits 16, //16 bit Z buffer size 0, //no stencil buffer 0, //no auxiliary buffer PFD_MAIN_PLANE, //main drawing plane 0, //reserved 0, 0, 0 }; //layer masks ignored //Choose best matching pixel format, return index nPixelFormat = ChoosePixelFormat(hDC, &pfd); //set pixel format to device context SetPixelFormat(hDC, nPixelFormat, &pfd); } //Event handler LRESULT CALLBACK WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) { static HGLRC hRC; //rendering context static HDC hDC; //device context char string[] = "Hello, world!"; //text to be displayed int width, height; //window width and height switch(message) { case WM_CREATE: hDC = GetDC(hwnd); //get current window''s device context g_HDC = hDC; SetupPixelFormat(hDC); //Call your pixel format setup function //create rendering context and make it current hRC = wglCreateContext(hDC); wglMakeCurrent(hDC, hRC); return 0; break; case WM_CLOSE: //deselect rendering context and delete it wglMakeCurrent(hDC, NULL); wglDeleteContext(hRC); //sent WM_QUIT to message queue PostQuitMessage(0); return 0; break; case WM_SIZE: height = HIWORD(lParam); //retrieve width and height width = LOWORD(lParam); if(height == 0) //don''t want a divide by zero { height = 1; } //Reset the viewport to new dimensions glViewport(0, 0, width, height); glMatrixMode(GL_PROJECTION); //set projection matrix glLoadIdentity(); //reset projection matrix //calculate aspect ratio of window gluPerspective(45.0f, (GLfloat)width/(GLfloat)height, 1.0f, 1000.0f); glMatrixMode(GL_MODELVIEW); //Set modelview matrix glLoadIdentity(); //reset modelview matrix return 0; break; default: break; } return(DefWindowProc(hwnd, message, wParam, lParam)); } //main windows entry point int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nShowCmd) { WNDCLASSEX windowClass; //window class HWND hwnd; //Window handle MSG msg; //message bool done; //fill out the window class structure windowClass.style = sizeof(WNDCLASSEX); windowClass.style = CS_HREDRAW | CS_VREDRAW; windowClass.lpfnWndProc = WndProc; windowClass.cbClsExtra = 0; windowClass.cbWndExtra = 0; windowClass.cbWndExtra = 0; windowClass.hInstance = hInstance; windowClass.hIcon = LoadIcon(NULL, IDI_APPLICATION); //default icon windowClass.hCursor = LoadCursor(NULL, IDC_ARROW); //default arrow windowClass.hbrBackground = NULL; //don''t need background windowClass.lpszMenuName = NULL; //no menu //Register the window class if(!RegisterClassEx(&windowClass)) return 0; //class registered, so now create your window hwnd = CreateWindowEx(NULL, //extended style "MyClass", //class name "The OpenGL Window Application!",//app name WS_OVERLAPPEDWINDOW | WS_VISIBLE| //window style WS_SYSMENU | WS_CLIPCHILDREN | // WS_CLIPSIBLINGS, 100, 100,//x, y coordinate 400, 400,//width, height NULL, //handle to parent NULL, //handle to menu hInstance, //application instance NULL); //no extra params //Check if window creation failed if(!hwnd) return 0; ShowWindow(hwnd, SW_SHOW); //display the window UpdateWindow(hwnd); //update the window done = false; //loop variable while(!done) { PeekMessage(&msg, hwnd, NULL, NULL, PM_REMOVE); if(msg.message == WM_QUIT) //if you receive a WM_QUIT message? { done = true; } else { //do rendering here //clear screen and depth buffer glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); glLoadIdentity(); //Reset modelview matrix angle = angle + 0.1f;//Increase rotation angle counter if(angle >= 360.0f) { angle = 0.0f; //reset angle counter } glTranslatef(0.0f, 0.0f, -5.0f); //move back 5 units glRotatef(angle, 0.0f, 0.0f, 1.0f);//draw the rectangle glColor3f(1.0f, 0.0f, 0.0f); //set color to red glBegin(GL_TRIANGLES); //draw the triangle glVertex3f(0.0f, 0.0f, 0.0f); glVertex3f(1.0f, 0.0f, 0.0f); glVertex3f(1.0f, 1.0f, 0.0f); glEnd(); SwapBuffers(g_HDC); TranslateMessage(&msg); //translate/dispatch to envent queue DispatchMessage(&msg); } } return int(msg.wParam); // MessageBox(NULL, "\Hello, world!", "My first windows application", NULL); }

Share this post


Link to post
Share on other sites
quote:
Original post by EGD Eric
The book didn''t say to do that.
Yeah it does, on page 9. And on page 8 it tells you what to do to make sure your compiler can find it.

Share this post


Link to post
Share on other sites
Sorry I didn''t reply till now, I started a new job.
I tried downloading the source code from that site, but couldn''t find it. Nor is it on the CD that comes with the book.

You''re right of course: it does say so in the book. I figure they should have mentioned that again, because I had forgotten about it, having read the previous chapter on a previous day.

Now, I''ve followed page 8 & 9''s instructions implicitly:

I put the following files in a folder I created called "GL" in the include folder of visual studio.net:

GL.h
Glu.h
Glaux.h

I also put the lib files into the "Include" file. It still gives me: Unresolved external symbols. Here''s my code:



#define WIN32_LEAN_AND_MEAN

#include <windows.h>
//#include <OpenGL32.lib>
//#include <glu32.lib>
#include <gl/gl.h> //Standard OpenGL include
#include <gl/glu.h>//OpenGL utilities
#include <gl/glaux.h> //OpenGL auxiliary functions



//Global Variables
float angle = 0.0f; //Current angle of the rotating triangle
HDC g_HDC; //global device context

//Function to set the pixel format for the device
void SetupPixelFormat(HDC hDC)
{
int nPixelFormat; //your pixel format index

static PIXELFORMATDESCRIPTOR pfd = {
sizeof(PIXELFORMATDESCRIPTOR), //Size of the structure
1, //Version, always set to 1
PFD_DRAW_TO_WINDOW | //support window
PFD_SUPPORT_OPENGL | //support openGL
PFD_DOUBLEBUFFER, //support double buffering
PFD_TYPE_RGBA, //RGBA color mode
32, //go for 32 bit color mode
0, 0, 0, 0, 0, 0, //Ignore color bits, not used
0, //No alpha buffer
0, //Ignore shift bit
0, //No accumulation buffer
0, 0, 0, 0, //Ignore accumulation bits
16, //16 bit Z buffer size
0, //no stencil buffer
0, //no auxiliary buffer
PFD_MAIN_PLANE, //main drawing plane
0, //reserved
0, 0, 0 }; //layer masks ignored

//Choose best matching pixel format, return index
nPixelFormat = ChoosePixelFormat(hDC, &pfd);

//set pixel format to device context
SetPixelFormat(hDC, nPixelFormat, &pfd);
}

//Event handler
LRESULT CALLBACK WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
static HGLRC hRC; //rendering context
static HDC hDC; //device context
char string[] = "Hello, world!"; //text to be displayed
int width, height; //window width and height

switch(message)
{
case WM_CREATE:
hDC = GetDC(hwnd); //get current window''s device context
g_HDC = hDC;
SetupPixelFormat(hDC); //Call your pixel format setup function

//create rendering context and make it current
hRC = wglCreateContext(hDC);
wglMakeCurrent(hDC, hRC);
return 0;
break;
case WM_CLOSE:
//deselect rendering context and delete it
wglMakeCurrent(hDC, NULL);
wglDeleteContext(hRC);

//sent WM_QUIT to message queue
PostQuitMessage(0);
return 0;
break;
case WM_SIZE:
height = HIWORD(lParam); //retrieve width and height
width = LOWORD(lParam);

if(height == 0) //don''t want a divide by zero
{
height = 1;
}

//Reset the viewport to new dimensions
glViewport(0, 0, width, height);
glMatrixMode(GL_PROJECTION); //set projection matrix
glLoadIdentity(); //reset projection matrix

//calculate aspect ratio of window
gluPerspective(45.0f, (GLfloat)width/(GLfloat)height, 1.0f, 1000.0f);

glMatrixMode(GL_MODELVIEW); //Set modelview matrix
glLoadIdentity(); //reset modelview matrix

return 0;
break;

default:
break;
}
return(DefWindowProc(hwnd, message, wParam, lParam));
}

//main windows entry point
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nShowCmd)
{
WNDCLASSEX windowClass; //window class
HWND hwnd; //Window handle
MSG msg; //message
bool done;

//fill out the window class structure
windowClass.style = sizeof(WNDCLASSEX);
windowClass.style = CS_HREDRAW | CS_VREDRAW;
windowClass.lpfnWndProc = WndProc;
windowClass.cbClsExtra = 0;
windowClass.cbWndExtra = 0;
windowClass.cbWndExtra = 0;
windowClass.hInstance = hInstance;
windowClass.hIcon = LoadIcon(NULL, IDI_APPLICATION); //default icon
windowClass.hCursor = LoadCursor(NULL, IDC_ARROW); //default arrow
windowClass.hbrBackground = NULL; //don''t need background
windowClass.lpszMenuName = NULL; //no menu

//Register the window class
if(!RegisterClassEx(&windowClass))
return 0;

//class registered, so now create your window
hwnd = CreateWindowEx(NULL, //extended style
"MyClass", //class name
"The OpenGL Window Application!",//app name
WS_OVERLAPPEDWINDOW | WS_VISIBLE| //window style
WS_SYSMENU | WS_CLIPCHILDREN | //
WS_CLIPSIBLINGS,
100, 100,//x, y coordinate
400, 400,//width, height
NULL, //handle to parent
NULL, //handle to menu
hInstance, //application instance
NULL); //no extra params

//Check if window creation failed
if(!hwnd)
return 0;

ShowWindow(hwnd, SW_SHOW); //display the window
UpdateWindow(hwnd); //update the window


done = false; //loop variable

while(!done)
{
PeekMessage(&msg, hwnd, NULL, NULL, PM_REMOVE);

if(msg.message == WM_QUIT) //if you receive a WM_QUIT message?
{
done = true;
}
else
{
//do rendering here
//clear screen and depth buffer
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glLoadIdentity(); //Reset modelview matrix

angle = angle + 0.1f;//Increase rotation angle counter
if(angle >= 360.0f)
{
angle = 0.0f; //reset angle counter
}
glTranslatef(0.0f, 0.0f, -5.0f); //move back 5 units
glRotatef(angle, 0.0f, 0.0f, 1.0f);//draw the rectangle

glColor3f(1.0f, 0.0f, 0.0f); //set color to red
glBegin(GL_TRIANGLES); //draw the triangle
glVertex3f(0.0f, 0.0f, 0.0f);
glVertex3f(1.0f, 0.0f, 0.0f);
glVertex3f(1.0f, 1.0f, 0.0f);
glEnd();

SwapBuffers(g_HDC);

TranslateMessage(&msg); //translate/dispatch to envent queue
DispatchMessage(&msg);
}
}
return int(msg.wParam);
// MessageBox(NULL, "\Hello, world!", "My first windows application", NULL);
}


Share this post


Link to post
Share on other sites
hey you cannot include libs by
#include
but they are included with

#pragma comment(lib,"xxx.lib")

(and (of course) they have to be copied to your Lib directory)

---why don''t we have assembler forum?--

Share this post


Link to post
Share on other sites
libs arent included, they are linked and thats usually not done in the source code (except that proprietary vc pragma stuff).

i still cant imagine the book telling you to copy it to the include directory or to use include.

Share this post


Link to post
Share on other sites
quote:
Original post by Trienco
i still cant imagine the book telling you to copy it to the include directory or to use include.
No, it doesn''t.

Share this post


Link to post
Share on other sites
Notice that the .lib includes are commented out?

I'm going to tell you what the book told me, so I can explain why I did what I did:

Page 8
------

Your compiler's directory should have a subdirectory for header files called something like "include". It should also have a subdirectory for libraries called something like: "lib.". look in the headers directory for a subdirectory called "gl", which should contain the files gl.h, glu.h and glaux.h. Then look in the libraries directory for the files opengl32.lib, glu32.lib, and glaux.lib. In the unlikely event that any of these files are missing, we've included the necessary files on the CD-ROM. Find the file called opengl.exe. Extract this file, and copy the libraries into the library folder for your compiler. Then create a subdirectoy called "gl" in your headers directory and copy the headers into it.

I found an include file at this location:

C:\Program Files\Microsoft Visual Studio .NET\Vc7\include
So I put the GL file in there:
C:\Program Files\Microsoft Visual Studio .NET\Vc7\include\GL

Once all of these files are present, the last step is to make sure you have the latest OpenGL drivers for your video card. Thse can be obtained from your video card manufacturer's web site or by using the free GLSetup utility at

Then it told me how to get the compiler to find the files by going into tools->options (directories tab).

I also went into the project menu and added the libraries to the Object "library modules" line.

Anyway, I do that, and then I copy down the code from a later page:

page 48
-------
The code is there, exactly the same as I posted it (minus the .lib includes; I don't even remember why I put those there)

Still doesn't work. I've tried this again with visual C++ 6, but that doesn't work either.

Edit:
Actually, I can't even find any "Includes" or "lib" folders in the visual C++ 6 thing anymore, don't know what's up with that.
But this should all work with .net anyway, right?



[edited by - EGD Eric on August 16, 2003 7:40:43 PM]

Share this post


Link to post
Share on other sites
i cant see anything wrong. the book is talking about the library folder, so this "I also put the lib files into the "Include" file." makes no sense. if you set your folders in vc and added the libs to the project it has to work. if the error is still the same, then it cant find the lib and the reason for that usually is wrong or no paths set.

Share this post


Link to post
Share on other sites
i cant see anything wrong. the book is talking about the library folder, so this "I also put the lib files into the "Include" file." makes no sense.

I never said I did that. I put the lib files in the lib folder, and the ".h" files in the GL folder (which I added to the include folder)


if the error is still the same, then it cant find the lib and the reason for that usually is wrong or no paths set.

I''m sorry but I''m not sure what you''re talking about. "No paths set?" You mean in the tools->options menu? Where you set the filepaths for includes and libs?



Look, I don''t know what the F*** the book is talking about by "header directory". I went to the include directory, made a folder in it called: "GL".

Ok, I''ll show you what I found in the vc7 subdirectory of my compiler''s directory. I didn''t change anything, they were already there:

Bin
Include
Lib
crt
PlatformSDK

yadayada...


It should also have a subdirectory for libraries called something like: "lib.".

I''ve been trying this sample program with both C++.net and c++ 6. The examples are explicitly for the older version of my compiler. In 6 I can go into projects->settings then add the library modules I want to use. I don''t know what the equivalent is for that in .net.

I tried to do this program with a trial version of C++6, but it does something strange when I build. It simply gives me the message it always gives before something is about to run (This is a trial version You cannot sell this, etc..) But that''s it.

Share this post


Link to post
Share on other sites
If you have Visual Studio properly installed you shouldn''t have to mess around with files.

At the top of your .cpp file,


#include <GL/gl.h>
#include <GL/glu.h>


In your project settings, add the following to the list of libraries you want to link to:

opengl32.lib
glu32.lib

I don''t have glaux, so you''ll have to do similar with regard to that.

If you still get errors, copy and paste the exact error messages here.

Good luck!


Why you shouldn''t use iostream.h - ever! | A Good free online C++ book

Share this post


Link to post
Share on other sites
I installed it(C++.net) by default completely, but those files still weren''t there. I had to copy them from the directory of a later installed trial version of Visual C++6.

In your project settings, add the following to the list of libraries you want to link to:

opengl32.lib
glu32.lib


That''s just it! I said in my previous posts that I already did that, but it just won''t work! (No errors, the application just doesn''t DO anything! (This is with the C++6 version of the project)

I didn''t do it with my .net version of the project, because there isn''t a Project->settings command! There''s no place where I can tell it to link to libraries! So with the .net version of the project, I get the same old errors:

OpenGLTriangle error LNK2019: unresolved external symbol __imp__glBegin@4 referenced in function _WinMain@16

Share this post


Link to post
Share on other sites
im pretty sure that the .net documentation (handbook or whatever) also tells you where to link libs. also that would be a good time to throw away the crutches and learn doing the basic things yourself instead of via a graphical ide. most compilers are command line and have no "project settings" either.

if it is working but "not doing anything" you should just have to step through it step by step with the debugger and find out whats wrong.

if thats still not helping/working it means that you should first learn c/c++ before you try doing anything more or less advanced with it.

Share this post


Link to post
Share on other sites
quote:
Original post by ShlomiSteinberg
You are not linking to OpenGL32.lib and glu32.lib.

"C lets you shoot yourself in the foot rather easily. C++ allows you to reuse the bullet!"


It''s not OpenGL32.lib its all in lowercase

right click on your project and click on settings, then goto the link tab, and type it there make sure theres a space in between otherwise it wont work

Share this post


Link to post
Share on other sites
1) Fired up dev studio 2002 Professional
2) File/New/Project
3) Selected C++/Win32 Project, Name: OpenGlTest, Location: C:\Source Code\C++\Test, then OK
4) Hit Application Settings, checked empty project, hit Finish
5) Right mouse on the project, Add/New Item, highlighted "C++ File", Name: OpenGlTest.cpp, hit Open
6) Pasted your code in (the code from your first post).
7) Right mouse click on the project select Properties, changed the configuration to be "All Configurations"
8) In the tree select Configuration Properties/Linker/Input. In the first field "Additional Dependencies" put:
opengl32.lib glu32.lib
9) hit OK
10) Hit F5 to run. Program exits early. Tracing in the debugger shows that RegisterClassEx is failing.
11) Fix the typo at line 115:

windowClass.style = sizeof(WNDCLASSEX);

to be

memset( &windowClass, 0, sizeof(WNDCLASSEX) );
windowClass.cbSize = sizeof(WNDCLASSEX);

in addition to zero initializing the structure. I also add a windows class name that matches the one in the CreateWindow() call:

windowClass.lpszClassName = "MyClass";

12) I hit F5 and rebuild and it now runs.



[edited by - mauman on August 20, 2003 3:26:20 PM]

Share this post


Link to post
Share on other sites
In C++ builder 5, (includes opengl and stuff useing some weird mechanism on its own...)

I took first post code pasted it into a blank .cpp file.
changed the

windowClass.cbSize = sizeof(WNDCLASSEX);
windowClass.cbWndExtra = 0;
windowClass.lpszClassName = "MyClass";
windowClass.style = CS_HREDRAW | CS_VREDRAW;
windowClass.lpfnWndProc = WndProc;
windowClass.cbClsExtra = 0;
windowClass.cbWndExtra = 0;
windowClass.cbWndExtra = 0;
windowClass.hInstance = hInstance;
windowClass.hIcon = LoadIcon(NULL, IDI_APPLICATION); //default icon
windowClass.hCursor = LoadCursor(NULL, IDC_ARROW); //default arrow
windowClass.hbrBackground = NULL; //don''t need background
windowClass.lpszMenuName = NULL; //no menu

to be as it reads above, reloaded it to make a project file. hit run, it ran.

it shows a nifty red triangle rotating around the central z axis..

Before I changed the befoce code, it ran and closed itself with out doing anything. so in essence it did nothing.

Share this post


Link to post
Share on other sites
If you want to save time, skip the first 2 paragraphs.
They are directed at Siaspete and Trienco.

Actually, I already know how to program. I'm just wet around the ears. I've already have a good grasp of the C++ language. I once made a 2-player chess program in C that was a bitch for me to debug (at the time). I've done file writing, operator overloading and templated linked lists, among other things. I've only worked in simple console before. When I learn something new, I like to start off with theory, then mimicking (copying and pasting) then tweaking with it, then More theory, then either repeat the steps or do whatever else I decide to do.
As I go, I use less and less "Crutches". This may not be how you learn, but its how I learn. You may have taught yourself, but ALL of MY programming skill comes from school. I just finished my first year, before which I didn't know much at all about computers.

Don't take your knowledge for granted. Some people just aren't as knowledgable and/or possessing as much "Computer sense" as you do. It doesn't mean I'm taking shortcuts or being lazy, its because its the only way I know how for now. If you can tell me a better way of doing it, maybe I'll try that.


I've implemented the changes in the C++6 project and it still exits early. This happens at line 131:

if(!RegisterClassEx(&windowClass))
return 0;

it seems to register the class okay, but then it skips
to the bottom line of this function call:

hwnd = CreateWindowEx(NULL,//extended style "MyClass",//class name "The OpenGL Window Application!",//app name
WS_OVERLAPPEDWINDOW | WS_VISIBLE| //window style
WS_SYSMENU | WS_CLIPCHILDREN | //
WS_CLIPSIBLINGS,
100, 100,//x, y coordinate
400, 400,//width, height
NULL, //handle to parent
NULL, //handle to menu
hInstance, //application instance
NULL); //no extra parameters

At this point hwnd is still NULL, which means it must not have Created the window. I can't step into the CreateWindowEx function because the compiler skips the lines for some reason.

if(!hwnd)
return 0;
This is where the program ends.

I tried this with C++6.

I'm gonna look into the .net development environment now, read the docs and stuff.


Edit: I just ran into something on the .net docs!
Its a Direct 3D tutorial! It showed the CreateWindow function, instead of the CreateWindowEx function, I tried this and it worked!

hwnd = CreateWindow("My Class", "The OpenGL Window Application!", WS_OVERLAPPEDWINDOW,
100, 100, 400, 400, GetDesktopWindow(), NULL, windowClass.hInstance, NULL);

[edited by - EGD Eric on August 21, 2003 2:37:34 PM]

Share this post


Link to post
Share on other sites
If you use the same code from before you had two bugs in your window class code which may have caused your CreateWindow() call to fail. One was your window class name was missing. This is what the 1st argument to CreateWindow and the 2nd argument to CreateWindowEx use to find the class you registered. Second, you were setting the stype field to be the structure size not the cbSize field. Aslo, you should zero initialize your structures in windows in case you do not explicitly set all of the fields.

With that said your registration code should look like:

//fill out the window class structure

memset( &windowClass, 0, sizeof(WNDCLASSEX));
windowClass.cbSize = sizeof(WNDCLASSEX);
windowClass.lpszClassName = "MyClass";
windowClass.style = CS_HREDRAW | CS_VREDRAW;
windowClass.lpfnWndProc = WndProc;
windowClass.cbClsExtra = 0;
windowClass.cbWndExtra = 0;
windowClass.cbWndExtra = 0;
windowClass.hInstance = hInstance;
windowClass.hIcon = LoadIcon(NULL, IDI_APPLICATION); //default icon

windowClass.hCursor = LoadCursor(NULL, IDC_ARROW); //default arrow

windowClass.hbrBackground = NULL; //don't need background

windowClass.lpszMenuName = NULL; //no menu


//Register the window class

if(!RegisterClassEx(&windowClass))
return 0;


You should find that this works on VC6, VC7 (Visual Studio .Net 2002), and VC7.1 (Visual Studio .Net 2003)


[edited by - mauman on August 21, 2003 4:24:31 PM]

Share this post


Link to post
Share on other sites