Jump to content
The simFlight Network Forums

dazz

Members
  • Posts

    104
  • Joined

  • Last visited

Everything posted by dazz

  1. I just added the sleep when I realised that I was still getting the same value that I had already in the function param, just to make sure that I could read the new value from the axis, but the moment I saw in the logs that with a 100ms sleep each iteration took like 116ms (as expected in such a simple piece of code), I new that wasn't going anywhere (almost a 90% of the time waiting for the new value, totally unacceptable). And yes, I tried the FSUIPC built in filter and it works very well. Actually I remember having set that in the past, but totally forgot about it. Knowing all these features much better now I hope that will translate soon in some other application that doesn't involve reinventing the wheel, hehe. I know now what to expect in terms of performance and thread management, and that will definitely help make better decisions for future scripts, know what to use and when, and of course I'll try to come up with a better idea to solve the problem next time than this one for the spikes. Taking for granted that there would be no consecutive spikes is a big limitation for a start, but well, as I said, ever since you reminded me about the FSUIPC filter, rather than optimizing the code, I was more interested in gathering the relevant information about how the pluggins run, and how the different features work. Thanks for the new suggestion for the problem, but I think it doesn't make sense to waste more time with this when there's already a much more capable filter available I just printed the advanced user guide, the FSUIPC4 Offsets Status.pdf, and the Lua Library.pdf for future reference. Maybe I could try to do something about "noise", but that's going to be much more difficult and my throttles don't suffer from that (yet) so there's no way I could test the script anyway I have a last question if you don't mind me asking. Regarding axis calibration, when you write directly to the FS control and with no axis assigned to FSUIPC like in the event.param version (it's assigned to LuaValue pluginName), how is it that the calibration works? I tried it and it works, but I thought the axis needed to be assigned via FSUIPC for the calibration to work
  2. I just explained why that version doesn't work properly: it will ignore the last ipcPARAM in the series of calls so the lever won't move all the way to the end. Nothing to do with the changes you kindly provided, it's a problem inherent to my original implementation. It discards the max and min values of the new1, new2, and ipcPARAM. Moving the lever in one direction, ipcPARAM will allways be discarded until the next iteration Try moving the lever fast and you will see the effect is quite apparent. As I said, that's why my first option was a loop polling the axes. It made things very simple, but obviously very inneficient too. I need a post-event reading of the axes output with this approach... or simply a different way of programming this.
  3. I don't think you need to change anything in the docs or anywhere else, just that I didn't make myself clear enough. You said that I need three values. That's the key here, and why I was trying to read the axis in the function, to get that third value. So I have the old value (old2), the newV value (ipcPARAM), and the third, the one I was trying to read from the 3332 offset (next). What I end up with is something like this: old2 = -16384 function throttle2(off, newV) ipc.log("old2 " .. old2) ipc.log("newV " .. newV.) nextV = ipc.readSW(0x3332) ipc.log("next " .. nextV) if not (newV > nextV and newV > old2) and not (newV < nextV and newV < old2) then nextV = newV end ipc.writeSW(0x0924, nextV) old2 = nextV ipc.log("Value sent -------------------------- " .. nextV) end ipc.writeUB(0x310A, logic.Or(ipc.readUB(0x310A), 128)) event.offset(0x3332, "SW", "throttle2") 327196 LUA: old2 -16384 327196 LUA: newV 0 327196 LUA: next 0 327227 LUA: Value sent -------------------------- 0 331533 LUA: old2 0 331533 LUA: newV 69 331533 LUA: next 69 331548 LUA: Value sent -------------------------- 69 331580 LUA: old2 69 331580 LUA: newV 979 331580 LUA: next 979 331611 LUA: Value sent -------------------------- 979 331658 LUA: old2 979 331658 LUA: newV 3575 331658 LUA: next 3575 331673 LUA: Value sent -------------------------- 3575 331704 LUA: old2 3575 331704 LUA: newV 6033 331704 LUA: next 6033 331736 LUA: Value sent -------------------------- 6033 So ipcPARAM is always the same as ipc.readSW(0x3332)... unless I add a sleep(100): old2 = -16384 function throttle2(off, newV) ipc.log("old2 " .. old2) ipc.log("newV " .. newV.) ipc.sleep(100) nextV = ipc.readSW(0x3332) ipc.log("next " .. nextV) if not (newV > nextV and newV > old2) and not (newV < nextV and newV < old2) then nextV = newV end ipc.writeSW(0x0924, nextV) old2 = nextV ipc.log("Value sent -------------------------- " .. nextV) end ipc.writeUB(0x310A, logic.Or(ipc.readUB(0x310A), 128)) event.offset(0x3332, "SW", "throttle2") Output log: 904961 LUA: old2 -16384 904961 LUA: newV 0 905055 LUA: next 0 905071 LUA: Value sent -------------------------- 0 905679 LUA: old2 0 905679 LUA: newV 1403 905773 LUA: next 3524 905804 LUA: Value sent -------------------------- 1403 905804 LUA: old2 1403 905804 LUA: newV 6703 905897 LUA: next 9443 905929 LUA: Value sent -------------------------- 6703 905929 LUA: old2 6703 905929 LUA: newV 12743 906038 LUA: next 14710 906053 LUA: Value sent -------------------------- 12743 With the sleep it works fine, because I'm actually reading a third value to compare to the other two. Of course ipcPARAM is no solution since it's not a new value, no matter if I put the thread to sleep waiting for the axis to update, because ipcPARAM is the same thing as the function parameter. Next: function throttle2(off, newV) ipc.sleep(100) nextV = ipc.readSW(0x3332) if not (newV > nextV and newV > old2) and not (newV < nextV and newV < old2) then nextV = newV end ... the "if" clause only compares newV (ipcPARAM) to old2 and nextV (the 3rd value). And this is why: I assume there will not be two consecutive spikes. We assume for now that "old" was not a spike, because it was stored in a previous iteration after the filtering. "Old" was the value sent to the offset after filtering. Now we have newV (ipcPARAM) and nextV. 1.- If nextV is a spike: old = 1000 newV= 2000 *applied* nextV = 6666 the filter will discard nextV, and the next iteration when the spike is gone: old = 2000 newV= 2000 nextV = 2000 *applied* If newV is a spike: old = 1000 newV = 6666 nextV = 2000 *applied* It can happen something like this: old = 1000 newV = 1666 *spike* *applied* nextV = 2000 But if the spike is small enough to stay in between old and nextV it won't hurt to allow that value to be written to the axis Now, why do I need to get the third value from the function itself? Because I need the output to stabilize to the latest valid value. If I store two old values and just use the latest ipcPARAM as the third, let's say that I'm pushing the throttle all the way to full throttle: old1 = 12000 old2 = 14000 *applied* newV = 16000 The lever will stop at 14000 even though 16000 is a valid value. If I read my third value in the function: old = 14000 (or whatever) newV = 16000 nextV = 16000 *applied* So the lever will stop at full throttle as expected. This is the reason why I was polling the axes in the first place, to avoid the levers to stop too early in an event driven implementation. And this is the workaround I thought for the event driven version: reading the third value IN THE FUNCTION, after the event is sent. I need the sleep clause because without it, the nextV is read too fast and it will actually be the one provided by ipcPARAM. Adding a delay is not an option really, so I will have to consider a new way to do this. I hope that helps clarifying things a bit, and again your help and your time are VERY MUCH APPRECIATED :)
  4. Pete, take it easy please. I appreciate your help very much and I definitely tried your version with the prevV thing, but as I explained earlier it's not needed anymore with the last version. I'm not polling the axis anymore, and I'm storing the old/previous value for calulation porposes, never to apply that again. In an event driven approach, the new value will most likely not be the same as the previous one, so no need for checking if they are different before updating the axis. I even placed a log line in the else part to make sure it wasn't actually trying to aplly a value to the offset that was already the same one. I know ipcPARAM is the same as the parameter passed to the function, that was my question, because I need a new value with this implementation as I said. A new value that ipc.readSW(0x3332) does actually provide unlike ipcPARAM. The crappy calibration in the code is back there just so I could test the relevant part for me here, that is the ability to read the axis inside the function like with ipc.readSW(0x3332) in the offset event version I'm not saying you should change anything, I'll find a way around that or will simply go back to the offset events, was just trying to figure out how it works Thanks again for your time EDIT: I can see now that reading the axis right after the function is called returns the same value, so it's actually not filtering anything. It works if a put a sleep before I read the axis, but I don't want to do that for obvious reasons. I'll simply think of a different way to program this
  5. Ok, I have the updated docs now: old1 = -16384 function throttle1(newV) ipc.log("newV " .. newV) nextV = ipcPARAM ipc.log("nextV " .. nextV) if not (newV > nextV and newV > old1) and not (newV < nextV and newV < old1) then nextV = newV end old1 = nextV nextV = (nextV / 2) + 8192 ipc.writeSW(0x088C, nextV) end event.param("throttle1") I can see however that newV and nextV will always be the same
  6. Downloading now. Thanks Pete ...but looks like the Lua Plugins and docs in the zip file are not updated EDIT: question please. Did you add an ipc.getParam or something like that? If the ipcParam variable is tied to the plugin thread it's going to return the same value that was passed to the event.param function anyway. Is that right or will ipcParam be updated if the axis is moving while the event is being executed? Reason I ask is because in the last version I read the axis right after the event is triggered: nextV = ipc.readSW(0x3332) I then use newV nextV and old1 (the previous value applied) to calculate the next valid value. If I can do something like: nextV = ipc.getParam() where nextV will not necessarily be the same as the newV value passed to the function from ipcParam, then I'm fine. Otherwise I'll have to think of a different way to do this, or keep using the throttle disconnects and calibrated axes offset driven events.
  7. True, I misunderstood your first post where you clearly stated that in an event triggered solution the plug-in would be always there and running on demand Does this mean that a single thread is serving both events the same way it would with a sleep clause? If that's the case I think it's better to run each throttle in a separate pluggin EDIT: I put some ipc.log lines in both functions and it looks like it's actually a single thread Is that the reason why there can only be one timer per pluggin? Is the timer function also running in the same thread? Logs seem to confirm that also EDIT2: I simplified the code: old2 = -16384 function throttle2(off, newV) nextV = ipc.readSW(0x3332) if not (newV > nextV and newV > old2) and not (newV < nextV and newV < old2) then nextV = newV end ipc.writeSW(0x0924, nextV) old2 = nextV end event.offset(0x3332, "SW", "throttle2") In the event driven version I don't really need to check if the previous value equals the new one, since the function is called when the lever is actioned so most of the times it will be a new value. I'm not polling the axis anymore, so I can skip that and make the code simpler. I also store the filtered value as the "old" one, so if a reading is discarded as a probable spike, it won't be used for further calculations. This "old" or previous value is compared to the one that triggered the event (newV) and a new reading (nextV). The new reading is to make sure that the last value is not unnecessarily discarded, so in normal conditions, the last time the event is triggered (when the lever is realeased) nextV and newV will be the same. I have another pluggin for the throttle2 and a third one for the axes disconnects. With ipcParam I'll get rid of the last one since I won't need to assign the throttles to the axes, but to the Lua pluggins instead
  8. I just added the prevV check and the code looks like this now. I know I could encapsulate things in functions, but it's a bit more compact like this... that and because I'm a lazy bum :P Runs flawlessly, no crashes at all, even though there's no reason left for this anymore but I'll hang on just for the fun of it, and it will help with future scripts ipc.set("old11", -16384) ipc.set("old12", -16384) ipc.set("prev1V", -16384) ... function throttle1(off, new3) new1 = ipc.get("old11") new2 = ipc.get("old12") nextV = new3 if not (new2 > new3 and new2 > new1) and not (new2 < new3 and new2 < new1) then nextV = new2 end if not (new1 > new3 and new1 > new2) and not (new1 < new3 and new1 < new2) then nextV = new1 end new1 = new2 new2 = new3 new3 = ipc.readSW(0x3330) ipc.set("old11", new2) ipc.set("old12", new3) nextV = new3 if not (new2 > new3 and new2 > new1) and not (new2 < new3 and new2 < new1) then nextV = new2 end if not (new1 > new3 and new1 > new2) and not (new1 < new3 and new1 < new2) then nextV = new1 end if nextV ~= prev1V then --ipc.control(66420, nextV) ipc.writeSW(0x088C, nextV) prev1V = nextV end end function throttle2(off, new3) ... end function resetBits() ipc.writeUB(0x310A, logic.Or(ipc.readUB(0x310A), 64)) ipc.writeUB(0x310A, logic.Or(ipc.readUB(0x310A), 128)) end event.offset(0x3330, "SW", "throttle1") event.offset(0x3332, "SW", "throttle2") event.timer(5000, "resetBits") resetBits() There's something about the event.param solution that I'm not sure about. Is it shared globally? I mean if I have both axes writing there how do I know what offset fired the event.param? You're also using local variables in an event driven implementation? I would have thought that every time an event triggers the action, it runs in a separate instance... time to test it myself :)
  9. Ok, I did it again. Should have thought of that. Thanks I have a timer based version ready to test, using local variables so hope that puts an end to the crashes. I'll get back to you with more relevant info if it keeps happenning, but I'm pretty sure everything will be ok I can't seem to get these Saitek axes working properly via FSUIPC calibration due to the -16K ~ 16K range thing, so I can't use the built in filter. What I could do is to use the calibration to filter the axes, and then intercept the post calibration offset to apply the (nextV / 2) + 8192 correction EDIT: ok, I just needed to check the "No Reverse Zone" option. Damn it, this is embarrasing :)
  10. <br>It's much smoother with two separate pluggins. Guess it has to do with the yield in between statements<br> <br>I was obviously talking about the thread to reset the bits for throttle disconnects, not the one to intercept the throttles<br> <br>There doesn't seem to be a built-in timer implementation in Lua, nor can I find any info about timers in the documentation or the examples provided. What do you use for a timer please?<br><br>By the way, I keep getting FSUIPC.dll crashes no matter what.<br> <br>On a side note, the script work ok with spikes, but it doesn't help much with noise induced by other levers, and I'm not sure there's nothing a reasonably simple script can do about it
  11. Event triggered, same idea. Works great with one axis. when I run the second one it crashes within seconds ipc.set("old11", -16384) ipc.set("old12", -16384) ipc.writeUB(0x310A, logic.Or(ipc.readUB(0x310A), 64)) function throttle1(off, new3) new1 = ipc.get("old11") new2 = ipc.get("old12") nextV = new3 if not (new2 &gt; new3 and new2 &gt; new1) and not (new2 &lt; new3 and new2 &lt; new1) then nextV = new2 end if not (new1 &gt; new3 and new1 &gt; new2) and not (new1 &lt; new3 and new1 &lt; new2) then nextV = new1 end ipc.set("old11", new2) ipc.set("old12", new3) nextV = (nextV / 2) + 8192 ipc.writeSW(0x088C, nextV) end event.offset(0x3330, "SW", "throttle1") is there something that explains the crashes?
  12. tried that, but the levers move out of sync Yes, that's one of the things I had left to try. An independant thread that will do that every 8-9 seconds. Silly question, but just in case. ipc.sleep puts the thread to sleep and it's not an active wait right? or would it be better to use a timer triggered event fot this?
  13. For now I'm using a keypress, for debugging purposes Thanks for making me look as the idiot I am hahaha (ok, I don't need help with that). Yeah, I totally screwed up there :) I'm not using UseAxisControlsForNRZ. Actually I didn't even have the axes set in the calibration section *blush*, so no wonder the post-calibration offsets' output are not calibrated. I've tested so many configs that I mistakenly thought I had them calibrated via FSUIPC. Again, sorry about that Yes, the axes work like that ( -16K to +16K), and yes, it's an effin saitek TQ. Best advise would be to stay away from saitek stuff actually
  14. Next version, using the throttle disconnect offset. Now axes should be normally assigned to throttle 1 & 2 in FSUIPC: Throttle 1: ipc.set("old11", -16384) ipc.set("old12", -16384) while (true) do ipc.writeUB(0x310A, logic.Or(ipc.readUB(0x310A), 64)) new1 = ipc.get("old11") new2 = ipc.get("old12") new3 = ipc.readSW(0x3330) ipc.set("old11", new2) ipc.set("old12", new3) nextV = new3 if not (new2 &gt; new3 and new2 &gt; new1) and not (new2 &lt; new3 and new2 &lt; new1) then nextV = new2 end if not (new1 &gt; new3 and new1 &gt; new2) and not (new1 &lt; new3 and new1 &lt; new2) then nextV = new1 end nextV = (nextV / 2) + 8192 ipc.writeSW(0x088C, nextV) ipc.sleep(50) end Throttle 2 ipc.set("old21", -16384) ipc.set("old22", -16384) while (true) do ipc.writeUB(0x310A, logic.Or(ipc.readUB(0x310A), 128)) new1 = ipc.get("old21") new2 = ipc.get("old22") new3 = ipc.readSW(0x3332) ipc.set("old21", new2) ipc.set("old22", new3) nextV = new3 if not (new2 &gt; new3 and new2 &gt; new1) and not (new2 &lt; new3 and new2 &lt; new1) then nextV = new2 end if not (new1 &gt; new3 and new1 &gt; new2) and not (new1 &lt; new3 and new1 &lt; new2) then nextV = new1 end nextV = (nextV / 2) + 8192 ipc.writeSW(0x0924, nextV) ipc.sleep(50) end There's something wrong with this, because it tends to crash the sim very often. It happened also with the previous version, so time to try the event triggered approach Also, post-calibration readings don't seem to be actually calibrated, so I need to do that crappy adjustment to the axis value: nextV = (nextV / 2) + 8192
  15. Hola Jesús! :) This is what I got so far: Throttle_1: ipc.set("old11", -16384) ipc.set("old12", -16384) ipc.writeSW(0x66C0, -16384) while (true) do new1 = ipc.get("old11") new2 = ipc.get("old12") new3 = ipc.readSW(0x66C0) ipc.set("old11", new2) ipc.set("old12", new3) nextV = new3 if not (new2 &gt; new3 and new2 &gt; new1) and not (new2 &lt; new3 and new2 &lt; new1) then nextV = new2 end if not (new1 &gt; new3 and new1 &gt; new2) and not (new1 &lt; new3 and new1 &lt; new2) then nextV = new1 end nextV = (nextV / 2) + 8192 ipc.control(66420, nextV) ipc.sleep(30) end Throttle_2: ipc.set("old21", -16384) ipc.set("old22", -16384) ipc.writeSW(0x66D0, -16384) while (true) do new1 = ipc.get("old21") new2 = ipc.get("old22") new3 = ipc.readSW(0x66D0) ipc.set("old21", new2) ipc.set("old22", new3) nextV = new3 if not (new2 &gt; new3 and new2 &gt; new1) and not (new2 &lt; new3 and new2 &lt; new1) then nextV = new2 end if not (new1 &gt; new3 and new1 &gt; new2) and not (new1 &lt; new3 and new1 &lt; new2) then nextV = new1 end nextV = (nextV / 2) + 8192 ipc.control(66423, nextV) ipc.sleep(30) end You'll need to assign your throttles 1 & 2 to offsets 0x66C0 and 0x66D0 via Offset Dword Set and start the Lua pluggins in the Auto section of your 767, as you most than likely know already, but just in case someone else feels like giving it a try. Truth be told, my spiking is not that bad, so if you need a more agressive filtering let me know
  16. Yeah, I love the 310A thing. I'll do that. Now time to re-read the guide again before I ask any more unnecessary questions, should have noticed the PollInterval is described there, so sorry about that. I'll double check my delta value too That would be awesome, if it's something that won't take too long it would be a nice addition Thanks Pete
  17. Ok, it's working pretty well already, but I'd like to improve a couple of aspects. 1.- This is really no big deal, and guess there's nothing that can be done about it, but, is there a way to increase the rate at which the axis are polled? as it stands now I get readings slower than I'd like and it makes the throttles a bit jerky, and add some lag 2.- I'm using the 0x66C0 and 0x66D0 offsets at the moment, but I'd like to avoid that just in case someone is using them already, but can't think of a way to do this. Is there a way to pass a parameter to a Lua pluggin so that I assign the throttle axis to it and the pluggin updates a global variable with the new value of the axis? There's probably a better way to do this, so any suggestions are welcome
  18. Ok, then I guess I'll have to be careful not to overflow the call stack, but it's definitely a nice approach. Thanks again Pete
  19. Might as well keep it simple with just 3 readings and avoid the need of building a stack or a table, and also calculating the average. I'm testing with 3 readings and it works great already Ok, the timer event sound like a much more elegant solution, thanks for the suggestion. Do I need to worry about thread overlapping if the event is triggered when the previous one has not finished jet?
  20. Thanks Pete Yes, I have also considered intercepting the axis, but the idea is to pick the last n axis readings, discard the max and min value and apply the average of the rest. In an event driven approach I would be discarding the last reading even if it's a valid value. With the loop, the next iteration would ensure the proper value is applied. I will try different implementations including event driven, but for now that's what I'm trying to do A stack seems to fit my needs just perfectly with this approach since I can keep the last n relevant values updated naturally. I can see that Lua has a native implementation of a stack, but a table would do too. So, is there a way to store a complex structure like a stack or a table in the global space like ipc.set does please?, or maybe ipc.set works with any kind of data structure? I can always try that before asking hehe
  21. Hi everyone. I'm working in a script to filter my TQ spikes. It looks like this so far: while (true) do new1 = ipc.get("old1") new2 = ipc.get("old2") new3 = ipc.readSW(0x66C0) if new1 == nil then new1 = 0 end if new2 == nil then new2 = 0 end if new3 == nil then new3 = 0 end ipc.log("new1 = " .. new1) ipc.log("new2 = " .. new2) ipc.log("new3 = " .. new3) ipc.log("-----------------------") ipc.set("old1", new2) ipc.set("old2", new3) nextV = new3 if not (new2 &gt; new3 and new2 &gt; new1) and not (new2 &lt; new3 and new2 &lt; new1) then nextV = new2 end if not (new1 &gt; new3 and new1 &gt; new2) and not (new1 &lt; new3 and new1 &lt; new2) then nextV = new1 end nextV = nextV * -1 ipc.control(66504, nextV) ipc.log("nextV = " .. nextV) ipc.log("***********************") ipc.sleep(50) end It's of course in it's infancy yet. Couple questions please. I want to expand it to filter all 4 throttle axis independantly, and a stack would come in handy. 1.- Any suggestions on a stack implementation for Lua? Don't even need it to take care of concurrency, as I will only have one writer 2.- Can I store the stacks in the global just like ipc.set does or do I need to build the stacks for each iteration? If I can't I might as well forget about using "complex" data structures and keep it simple instead 3.- Also considering assigning the axis to a Lua pluggin that will update a global variable via ipc.set instead of using the 0x66C0 offset. What is the best approach performance wise? I take it when I assign my throttle axis to the 0x66C0 offset, FSUIPC is also running a thread to update the value the same way the Lua plugin would. Is that correct? ...more questions to come Thanks in advance
  22. For anyone interested, I uploaded a profile for this awesome plane here: http://vrinsight.com/phpBB3_en/viewtopic.php?f=9&t=1062&sid=43b4abf00b6b7475a599c9c30cbeba64
  23. Ahhhh, ok! so I would simply need to do something like this: WrFilter.1=<displayFilters> -- in the FSUIPC4.ini driver = com.open(VRIdriver, speed, handshake) device = com.open(VRIdevice, speed, handshake) title = ipc.readSTR(0x3D00,256) function filterDisplays(handle, str) if title = "LDS 767" then --forward to the driver com.write(driver, str, 8) else -- manage the displays myself end end event.VRIwrite(device, "filterDisplays") Fair enough, no need to mess around with the filters then. Thanks Pete
  24. Well, my question was quite stupid now I think of it: of course I know which A/C is in use since the lua plugin to be run depends on the [Auto] section that is set for each plane. Sorry about that. That 3D00 offset would do the trick too, thanks. Knowing the aircraft in use I know the profile in use too, so it is not really needed to query the profile. It would still be usefull to avoid needing to edit the Lua plugin each time an aircraft is added or removed from a certain profile, but still not something necessary. It would be nice to have that offset if and only if it's a really simple thing to do. The filtering is another story. If I got it right (this time), it will limit was is sent/received to/from the driver (SerialFP2) Each time a new aircraft is loaded the the right plugin in the A/C [Auto] section is executed for what I can see: wouldn't it be possible to dinamically load the filters for each plane/profile upon A/C loading? Of course I'm not aware of the implications and it's not a deal breaker anyway but the thing is that if I have for example the LSD767 upgrading properly the panel screens, but I would like to implement a screen refresh for a PMDG A/C, I would need to set different filters for each one if I got it right Again I think I got confused, that's not something I can control in the lua plugin right? I mean everything is sent/received to the driver unless you filter it?
  25. Have you tried this one? 05D0 The viewpoint Heading, *360/(65536*65536) for degrees TRUE.
×
×
  • 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.