Jump to content
The simFlight Network Forums

Get values via simconnect 'execute_calculator_code'


Recommended Posts

Posted

Dear @John Dowson, Dear @Paul Henty

I noticed, that it seems to be possible to get values via the execute_calculator_code function of Simconnect.
See: https://docs.flightsimulator.com/html/Programming_Tools/WASM/Gauge_API/execute_calculator_code.htm

As FSUIPC7 already supports execCalcCode and it works great "triggering" stuff with it, I'd like to make use of it on reading those values (and subscribing on value changes with the FSUIPC Websocket Server).

That it seems to be supported by SimConnect API and can be seen in places like Mobiflight where it is implemented.
Is that already possible with FSUIPC and its websocket server? If yes, how can this be done? If no... Is there a chance that we'll get it one day?

Best regards,

           Joe

Some probably usefull links:

  • https://docs.flightsimulator.com/html/Programming_Tools/WASM/Gauge_API/execute_calculator_code.htm
  • https://forums.flightsimulator.com/t/simconnect-wasm-combined-project-using-vs2019/486871/22?page=2
  • Mobiflight
  • image.png.c9ac82632ca2cbb9b9289954c0c5160c.png
  • https://hubhop.mobiflight.com/presets/ (select the "Outputs" to check what is run there.
  • image.png.19f26750e946bc31add551f8847933d0.png

    I tried it already from JS to "read" the
    L TK Pump 1 Off
     Annunciator LED value as defined within the FBW A32nx...
     
    let request = {command: 'vars.calc',name: 'calc',code: '(A:FUELSYSTEM PUMP SWITCH:2, Enum) 0 == (L:A32NX_OVHD_INTLT_ANN) 0 == or 1 and (L:A32NX_ELEC_AC_ESS_SHED_BUS_IS_POWERED, Bool) and (L:A32NX_OVHD_INTLT_ANN, number) 2 == if{ 0.1 } els{ 1 } * (A:CIRCUIT GENERAL PANEL ON, Bool) *'}
    let socket = new WebSocket("ws://myHost:2048/fsuipc", "fsuipc");
    
    socket.onopen = function(e) {
      console.log("[open] Connection established");
      socket.send(JSON.stringify(request));
    };
    
    socket.onmessage = function(event) {
      console.log(`[message] Data received from server: ${event.data}`);
    };
    
    socket.onclose = function(event) {
      if (event.wasClean) {
        console.log(`[close] Connection closed cleanly, code=${event.code} reason=${event.reason}`);
      } else {
        console.log('[close] Connection died');
      }
    };
    
    socket.onerror = function(error) {
      console.log(`[error] ${error.message}`);
    };

    And I received

  • {
      "command": "vars.calc",
      "name": "calc",
      "success": true,
      "errorMessage": null,
      "errorCode": null
    }

    So sucessfully sent the calculatorCode... But there is no return value nor any chance to subscribe for changes which I need to be able to update the annunciator LEDs in case the conditions change...

    Looking forward for your feedback,

    Joe

Posted (edited)
42 minutes ago, joeherwig said:

Is that already possible with FSUIPC and its websocket server?

No. However, there is a way around this. You can create your own lvar, have the calculator code write its result to an lvar, and then read the lvar value (or add it to an FSUIPC offset).

42 minutes ago, joeherwig said:

If no... Is there a chance that we'll get it one day?

As there is a relatively simple workaround (explained above), I am not planning to implement such a feature at the moment, although it could be something I could consider adding in the future.

Regards,

John

Later: ...and  many (most?) MF output presets are just the value of an lvar anyway - for those you can just read the lvar directly and not use presets. The one you are using uses a combination of lvars and simvars (a:vars). Rather than using calculator code, you can get the lvar and avar values (directly or via offsets) and embed the calculator code in your code.

Edited by John Dowson
Later added
Posted
1 hour ago, John Dowson said:

You can create your own lvar, have the calculator code write its result to an lvar,

But that needs to be done within the code of the aircraft? Doing that stuff on Aircraft side I already did successfully for the FBW A32nx in my branch.
But if the maintainers of the Aircraft decide "for performance reasons" not to add all those LVars to the aircraft...  it seems my pull request will not have a big chance to be accepted.

In the scope of FSUIPC7 I only found within the Advanced Users guide the section "Adding Lvars to Offsets" - but it seems that this doesn't help here, as for me there is no difference whether I read an LVar or an Offset. Both already works including the updating in case of changes.
ut I don't get the return value of the Calculator Code into that LVar...

Do you have probably somewhere else an example how I can get the result of the CalculatorCode execution into an LVAR so that changes are triggering to update the LVAR?
That would really help me a lot...

btw: Just found Pete's post from January 22, 2020 stating:

Quote

 

FSUIPC doesn't create L:Vars, it only provides facilities to read and write them.

Pete

 

 

Posted
13 hours ago, joeherwig said:

But that needs to be done within the code of the aircraft?

No. You can create and read lvars by using offset 0x0D70 (or via lua). Maybe also using calculator code - I think if you execute a calculator code string that writes to an lvar and that lvar doesn't exist, it will be created. It should be straightforward to test this using FSUIPC's WASM menu: execute dome calculator code that writes a value to a non-existent lvar, issue a reload and then list the lvars to see if the one you created exists with the value that you gave it.

13 hours ago, joeherwig said:

Do you have probably somewhere else an example how I can get the result of the CalculatorCode execution into an LVAR so that changes are triggering to update the LVAR?
That would really help me a lot...

To get the value of a calculator code string into an lvar, you would just execute the calculator code string:
      (<CalcCodeString>) (>L:myLvarToHoldCalcCodeStringResult)

13 hours ago, joeherwig said:

btw: Just found Pete's post from January 22, 2020 stating:

Quote

 

FSUIPC doesn't create L:Vars, it only provides facilities to read and write them.

Pete

 

Probably  bit misleading...FSUIPC doesn't create lvars, but does provide facilities for such. After you create the lvar (however you create it), you will need to issue a reload command to get the updated list of lvars, containing the new lvar you created, together with its current value.

John

  • Thanks 1
Posted
3 hours ago, John Dowson said:

I think if you execute a calculator code string that writes to an lvar and that lvar doesn't exist, it will be created.

Just tested this and this is the case. You can therefore create your lvar when you initialise and then issue a reload to make the lvar known to the WAPI. Then, you can execute the calculator code and write that value to an lvar (in the calc code, as shown), and the value should be available in that lvar, after a short delay - 200ms or so by default with a 6Hz refresh rate, but sooner if you increase the refresh rate.

John

Posted
2 hours ago, joeherwig said:

Do you know, whether the LVAR gets updated automatically on condition change? 

Yes, after a short delay - as I said:

2 hours ago, John Dowson said:

...and the value should be available in that lvar, after a short delay - 200ms or so by default with a 6Hz refresh rate, but sooner if you increase the refresh rate.

Or do you mean something else?

John

Posted

Well if I subscribe on LVar change events to get informed via the FSUIPC websocket serve, the value should be updated in the LVAR and the websocket update event fired, when the result of the calculatorCode calculation gets different, without the need of explicitly retriggering (polling) the calculatorCode... 

So I need it as an server send change event instead of regular client side requests aka polling.

As long as it works... Great. 

I'll also try to check it out... And many thanks for your investigation and updates. 

Joe

 

Posted
35 minutes ago, joeherwig said:

Well if I subscribe on LVar change events to get informed via the FSUIPC websocket serve, the value should be updated in the LVAR and the websocket update event fired, when the result of the calculatorCode calculation gets different, without the need of explicitly retriggering (polling) the calculatorCode... 

You need to execute the calculator code to update the lvar. If the lvar (that holds the result) changes value, then you would receive the update  value in exaclty the same way as you would get the value from any lvar (I haven't used the websocket server so cannot comment on that). Not sure what you mean by '...without the need of explicitly retriggering (polling) the calculatorCode... ' though...

Anyway, just try it and see how you get on....

Johh

Posted
4 hours ago, John Dowson said:

You need to execute the calculator code to update the lvar.

That's unuseable for me.

It's like calling the answering machine and entering the menu where I get told about the number of new voice messages each minute. So in >99% of the requests there is completely NO value but a lot of cost.
What I need instead, is that my answering machine (LVar) is informing me automatically if the number of new messages (here the result of the calculation) **changed**.

That's what happens with the websockets... You subscribe on change events and the system cares for you to monitor changes.

There is no sense in asking your buttler to inform you when the weather changes, but he will only take a look outside, when he is explicitly told by you.
So the buttler will obviously never notice on his own **that** the weather changed and thus will never inform you.

Not sure, whether i succeeded to make the difference between "request/response" and "event subscriptions" a bit more clear. Hope so...

Posted

Hi Joe,

Quote

without the need of explicitly retriggering (polling) the calculatorCode... 

If your calculator code is updating the LVar then it must be run at regular intervals. The only question is *where' it's being run at regular intervals. It seems like you don't want to do it in your code as it will result in a lot of network traffic.

Would it help if I enabled the 'interval' property for the 'vars.calc' command? The websocket server would then run the calc for you every x milliseconds. If you monitor the destination LVar with changesonly then you'll just get a message when the destination lvar changes.

Let me know if that sounds like a useable solution. But before I do the work, please check that you can indeed write to a new LVar from the calc code and read the resulting value back.

Paul

Posted
10 hours ago, joeherwig said:
15 hours ago, John Dowson said:

You need to execute the calculator code to update the lvar.

That's unuseable for me.

As well as what Paul has said, your original question, and title of this topic, is how to get values back  from a simconnect execute_calculator_code call - I explained that this was not possible but there is a workaround - you write the result of the calculator code to an lvar and then read the value of the lvar. You still need to execute the calculator code, as you would need to do if you were getting the value back from the execute_calculator_code call...

11 hours ago, joeherwig said:

Not sure, whether i succeeded to make the difference between "request/response" and "event subscriptions" a bit more clear. Hope so...

I completely understand this...and you can get a callback/event when an lvar changes. However, as this is YOUR lvar, you also need to provide the mechanism for it to get updated,,,

Paul has also provided a possible solution to this for you. 

  • Like 1
Posted
3 hours ago, Paul Henty said:

Let me know if that sounds like a useable solution. But before I do the work, please check that you can indeed write to a new LVar from the calc code and read the resulting value back.

Paul

I'll do so... Thanks a lot for your offer. As soon as I've got the results, I'll let you know. 

Joe 

Posted

Btw and fyi, the execute_calculator_code function is a Gauge API function, not a simconnect function. The SimConnect ClientData areas are used to communicate from the Client to the WASM (that implements the Gauge functions) and back, and so the underlying mechanism is inherently asynchronous.

  • Thanks 1
Posted
3 hours ago, John Dowson said:

Paul has also provided a possible solution to this for you. 

Seems to be true...
Just checked it. Your Hint how to assign the calculation result to an LVar works well. And getting the updates on reading as well. Not yet tested, wheter I also get the Updates via Websockets... Will do so.

Posted
13 hours ago, Paul Henty said:

Let me know if that sounds like a useable solution. But before I do the work, please check that you can indeed write to a new LVar from the calc code and read the resulting value back.

Hi @Paul Henty

TL;DR
Your suggested server-side retriggering would help a lot (if we're unable to use the calculatorCode to get the result as return value AND assign it to a LVar) 👍

As I'm not sure, whether a calculatorCode in a system/gauge like mentioned above 

(A:FUELSYSTEM PUMP SWITCH:2, Enum) 0 == (L:A32NX_OVHD_INTLT_ANN) 0 == or 1 and (L:A32NX_ELEC_AC_ESS_SHED_BUS_IS_POWERED, Bool) and (L:A32NX_OVHD_INTLT_ANN, number) 2 == if{ 0.1 } els{ 1 } * (A:CIRCUIT GENERAL PANEL ON, Bool) *

would still work within the aircraft if I add the LVar-Value assignment at the end.

(A:FUELSYSTEM PUMP SWITCH:2, Enum) 0 == (L:A32NX_OVHD_INTLT_ANN) 0 == or 1 and (L:A32NX_ELEC_AC_ESS_SHED_BUS_IS_POWERED, Bool) and (L:A32NX_OVHD_INTLT_ANN, number) 2 == if{ 0.1 } els{ 1 } * (A:CIRCUIT GENERAL PANEL ON, Bool) * (>L:A32NX_OVHD_FUEL_LTK1_PUMP_ANNUN)

If that's the case I see some chances that the LVars (adding and updating) could be better done within the Aircraft - which reduces the load for regular polling which would imho still the better variant.


My Tests
I checked it a bit more in detail and can state that when I "recalculate" by sending the "vars.calc" command, it updates the LVar and I get it via my subscribed event. 👍
I tested it with two LVars which I created via the vars.calc command as suggested by John and then regularely updating them via execCalcCode to a different value.

Here is my quick test from within the chrome browser console:

function Sleep(milliseconds) {
  return new Promise(resolve => setTimeout(resolve, milliseconds));
}

let putOwnVar = {command: 'vars.calc',name: 'calc',code: '0 (>L:A00000_JOE_TEST)'}
let putCockpitTemp = {command: 'vars.calc',name: 'calc',code: '(L:A32NX_COND_CKPT_TEMP) '+Math.random()+' * (>L:A00001_JOE_TEMP)'}
let reqAnnunToggle = {command: 'vars.calc',name: 'calc',code: '(L:A32NX_OVHD_INTLT_ANN) ! (>L:A32NX_OVHD_INTLT_ANN)'}
let reqJoeTestSync = {command: 'vars.calc',name: 'calc',code: '(L:A32NX_OVHD_INTLT_ANN) (>L:A00000_JOE_TEST)'}
let declare = {command: "vars.declare",name: "myVarSet",changesOnly: true,vars: [{ name: "A00001_JOE_TEMP" },{ name: "A00000_JOE_TEST"},{name: "A32NX_OVHD_INTLT_ANN"}]}
//let vars = {command: 'vars.list', name: 'list',notify: 'auto' }
let read = {command: "vars.read",name: "myVarSet",changesOnly: true, interval:200}
let socket = new WebSocket("ws://192.168.178.34:2048/fsuipc", "fsuipc");
let timerId = setInterval(() => {
  updateVars();
}, 2000);

socket.onopen = function(e) {
  socket.send(JSON.stringify(putOwnVar));
  Sleep(200); 
  socket.send(JSON.stringify(putCockpitTemp));
  Sleep(200); 
  socket.send(JSON.stringify(declare));
  Sleep(200); 
  socket.send(JSON.stringify(read));
  let timerId = setInterval(() => updateVars(), 5000);
  setTimeout(() => { clearInterval(timerId)}, 10000);
};

socket.onmessage = function(event) {
  console.log(`[message] Data received from server: ${event.data}`);
};

socket.onclose = function(event) {
  if (event.wasClean) {
    console.log(`[close] Connection closed cleanly, code=${event.code} reason=${event.reason}`);
  } else {
    console.log('[close] Connection died');
  }
};

socket.onerror = function(error) {
  console.log(`[error] ${error.message}`);
};

function updateVars(){
  socket.send(JSON.stringify(putCockpitTemp));
  Sleep(200); 
  /*
  socket.send(JSON.stringify(reqAnnunToggle));
  Sleep(200); 
  */
  socket.send(JSON.stringify(reqJoeTestSync));
}

  

@John Dowson I noticed, that my own LVars remained available within FSUIPC "even after closing and restarting FSUIPC. How can I get rid of these test-LVars?

@Paul Henty Is it correct, that the "vars.reload" request is triggering the WASM "Reload & list lvar" function as within FSUIPC?

2023-01-20_095501-Norma Connect - im besten Netz.png

Posted
9 hours ago, joeherwig said:

I noticed, that my own LVars remained available within FSUIPC "even after closing and restarting FSUIPC. How can I get rid of these test-LVars?

Try changing aircraft and then restart...

10 hours ago, joeherwig said:

Is it correct, that the "vars.reload" request is triggering the WASM "Reload & list lvar" function as within FSUIPC?

Note that the reload function shouldn't be needed in the next version of the WASM / WAPI, as it will periodically (at 6Hz) scan for new lvars and automatically push them to clients if/when found. I will release this version, as well as an FSUIPC7 7.3.17-beta, later today. The total number of lvars supported will also increase from 3066 to 9198.

John

  • Thanks 1
Posted
Quote

Your suggested server-side retriggering would help a lot (

Okay - I'll make the changes. I expect to have a new version out sometime next week.

I'll also update to the new WAPI library that John is releasing. 

Paul

Posted

New websocket server is now available (Version 1,1,1):

http://fsuipcwebsockets.paulhenty.com/

  • Uses new WAPI version 1.0.0 beta.
  • vars.calc now has 'interval' property to request repeated execution of calculator code. Time in milliseconds.
  • Stop the repeats with vars.stop command. (Use the same command name).
  • Multiple code requests can be repeated by using unique command names.

Paul 

  • Like 1
  • 4 weeks later...
Posted

Thanks @John Dowson, Thanks @Paul Henty

Succeeded now finally to try it out with 7.3.17 and 1.1.1 and I'm fully happy.
Really a HUGE improvement for my Annunciators.

If you like to try... The code I checked from browser console...

function Sleep(milliseconds) {
  return new Promise(resolve => setTimeout(resolve, milliseconds));
};

let reqJoeTestSync = {command: 'vars.calc',name: 'calc',code: '(A:FUELSYSTEM PUMP SWITCH:2, Enum) 0 == (L:A32NX_OVHD_INTLT_ANN) 0 == or 1 and (L:A32NX_ELEC_AC_ESS_SHED_BUS_IS_POWERED, Bool) and (L:A32NX_OVHD_INTLT_ANN, number) 2 == if{ 0.1 } els{ 1 } * (A:CIRCUIT GENERAL PANEL ON, Bool) * (>L:A20N_L_TK_Pump_1_Off)', interval: 200}
let declare = {command: "vars.declare",name: "myVarSet",changesOnly: true,vars: [{ name: "A20N_L_TK_Pump_1_Off" },{name: "A32NX_OVHD_INTLT_ANN"}]}
//let vars = {command: 'vars.list', name: 'list',notify: 'auto' }
let read = {command: "vars.read",name: "myVarSet",changesOnly: true, interval:200}
let socket = new WebSocket("ws://Simulator:2048/fsuipc", "fsuipc");

socket.onopen = function(e) {
  socket.send(JSON.stringify(reqJoeTestSync));
  Sleep(200); 
  socket.send(JSON.stringify(declare));
  Sleep(200); 
  socket.send(JSON.stringify(read));
};

socket.onmessage = function(event) {
  console.log(`[message] Data received from server: ${event.data}`);
};

socket.onclose = function(event) {
  if (event.wasClean) {
    console.log(`[close] Connection closed cleanly, code=${event.code} reason=${event.reason}`);
  } else {
    console.log('[close] Connection died');
  }
};

socket.onerror = function(error) {
  console.log(`[error] ${error.message}`);
};

 

  • Like 2
Posted

@Paul Henty hm... No idea, what happened.

The above script doesn't retrigger the calculator codes reliable as it seems.
The first read is correct, but afterwards I don't get any further updates.
For offsets the regular updates are fine.

btw:
Also got with Version V1.1.1 of FSUIPC WebSockets Server:

Quote

See the end of this message for details on invoking 
just-in-time (JIT) debugging instead of this dialog box.

************** Exception Text **************
System.InvalidOperationException: Value Dispose() cannot be called while doing CreateHandle().
   at System.Windows.Forms.Control.Dispose(Boolean disposing)
   at System.ComponentModel.Component.Dispose()
   at System.Windows.Forms.Control.Dispose(Boolean disposing)
   at FSUIPCWebSockets.Server.GUI.ctlPanel.Dispose(Boolean disposing)
   at System.ComponentModel.Component.Dispose()
   at FSUIPCWebSockets.Server.GUI.frmMain.setPanel()
   at System.Windows.Forms.Control.OnClick(EventArgs e)
   at System.Windows.Forms.Button.OnMouseUp(MouseEventArgs mevent)
   at System.Windows.Forms.Control.WmMouseUp(Message& m, MouseButtons button, Int32 clicks)
   at System.Windows.Forms.Control.WndProc(Message& m)
   at System.Windows.Forms.ButtonBase.WndProc(Message& m)
   at System.Windows.Forms.Button.WndProc(Message& m)
   at System.Windows.Forms.NativeWindow.Callback(IntPtr hWnd, Int32 msg, IntPtr wparam, IntPtr lparam)


************** Loaded Assemblies **************
mscorlib
    Assembly Version: 4.0.0.0
    Win32 Version: 4.8.9139.0 built by: NET481REL1LAST_B
    CodeBase: file:///C:/Windows/Microsoft.NET/Framework64/v4.0.30319/mscorlib.dll
----------------------------------------
FSUIPCWebSocketServer
    Assembly Version: 1.1.1.24
    Win32 Version: 1.1.1.24
    CodeBase: file:///C:/FSUIPC7/Utils/FSUIPCWebSocketServer.exe
----------------------------------------
System.Windows.Forms
    Assembly Version: 4.0.0.0
    Win32 Version: 4.8.9075.0 built by: NET481REL1LAST_C
    CodeBase: file:///C:/WINDOWS/Microsoft.Net/assembly/GAC_MSIL/System.Windows.Forms/v4.0_4.0.0.0__b77a5c561934e089/System.Windows.Forms.dll
----------------------------------------
System
    Assembly Version: 4.0.0.0
    Win32 Version: 4.8.9139.0 built by: NET481REL1LAST_B
    CodeBase: file:///C:/WINDOWS/Microsoft.Net/assembly/GAC_MSIL/System/v4.0_4.0.0.0__b77a5c561934e089/System.dll
----------------------------------------
System.Drawing
    Assembly Version: 4.0.0.0
    Win32 Version: 4.8.9032.0 built by: NET481REL1
    CodeBase: file:///C:/WINDOWS/Microsoft.Net/assembly/GAC_MSIL/System.Drawing/v4.0_4.0.0.0__b03f5f7f11d50a3a/System.Drawing.dll
----------------------------------------
System.Configuration
    Assembly Version: 4.0.0.0
    Win32 Version: 4.8.9032.0 built by: NET481REL1
    CodeBase: file:///C:/WINDOWS/Microsoft.Net/assembly/GAC_MSIL/System.Configuration/v4.0_4.0.0.0__b03f5f7f11d50a3a/System.Configuration.dll
----------------------------------------
System.Core
    Assembly Version: 4.0.0.0
    Win32 Version: 4.8.9139.0 built by: NET481REL1LAST_B
    CodeBase: file:///C:/WINDOWS/Microsoft.Net/assembly/GAC_MSIL/System.Core/v4.0_4.0.0.0__b77a5c561934e089/System.Core.dll
----------------------------------------
System.Xml
    Assembly Version: 4.0.0.0
    Win32 Version: 4.8.9032.0 built by: NET481REL1
    CodeBase: file:///C:/WINDOWS/Microsoft.Net/assembly/GAC_MSIL/System.Xml/v4.0_4.0.0.0__b77a5c561934e089/System.Xml.dll
----------------------------------------
System.Numerics
    Assembly Version: 4.0.0.0
    Win32 Version: 4.8.9032.0 built by: NET481REL1
    CodeBase: file:///C:/WINDOWS/Microsoft.Net/assembly/GAC_MSIL/System.Numerics/v4.0_4.0.0.0__b77a5c561934e089/System.Numerics.dll
----------------------------------------
System.Runtime.Serialization
    Assembly Version: 4.0.0.0
    Win32 Version: 4.8.9032.0 built by: NET481REL1
    CodeBase: file:///C:/WINDOWS/Microsoft.Net/assembly/GAC_MSIL/System.Runtime.Serialization/v4.0_4.0.0.0__b77a5c561934e089/System.Runtime.Serialization.dll
----------------------------------------
System.Data
    Assembly Version: 4.0.0.0
    Win32 Version: 4.8.9110.0 built by: NET481REL1LAST_B
    CodeBase: file:///C:/WINDOWS/Microsoft.Net/assembly/GAC_64/System.Data/v4.0_4.0.0.0__b77a5c561934e089/System.Data.dll
----------------------------------------
Accessibility
    Assembly Version: 4.0.0.0
    Win32 Version: 4.8.9032.0 built by: NET481REL1
    CodeBase: file:///C:/WINDOWS/Microsoft.Net/assembly/GAC_MSIL/Accessibility/v4.0_4.0.0.0__b03f5f7f11d50a3a/Accessibility.dll
----------------------------------------

************** JIT Debugging **************
To enable just-in-time (JIT) debugging, the .config file for this
application or computer (machine.config) must have the
jitDebugging value set in the system.windows.forms section.
The application must also be compiled with debugging
enabled.

For example:

<configuration>
    <system.windows.forms jitDebugging="true" />
</configuration>

When JIT debugging is enabled, any unhandled exception
will be sent to the JIT debugger registered on the computer
rather than be handled by this dialog box.


 

 

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
×
×
  • Create New...

Important Information

By using this site, you agree to our Terms of Use. Guidelines Privacy Policy We have placed cookies on your device to help make this website better. You can adjust your cookie settings, otherwise we'll assume you're okay to continue.