san_gr Posted November 27, 2009 Report Share Posted November 27, 2009 Hi everyone, I am building a project that simulates 2 elevators in a 5 floor building. This is controlled by a microcontroller through serial. I have set up the communication part using many event and case structures and everything seems to work fine except from one thing. When the microcontroller sends 0xFF i want labview to send back some information of the elevator (position, status, etc). The way i did it is, when I receive 0xFF I set a boolean ("req_info") to true. Then I have an event structure that triggers when "req_info" changes value. But it doesn't seem to work. Enabling the "Highlight Execution" I can see that the case structure sets the boolean to true but the event doesn't trigger. Doing some other tests I realized that the event structure can not monitor boolean indicators only boolean controllers. Is that right? And if so then how can I solve the above problem? I hope my post is not very confusing Quote Link to comment
Ton Plomp Posted November 27, 2009 Report Share Posted November 27, 2009 Your question is not unclear, the solution is quite easy, you should use a property node with the 'Value(signalling)' property, this will activate the event case. However I advise you to take a different framework either use a User Event or a Queued Message Handler or the JKI State Machine toolki. Ton Quote Link to comment
san_gr Posted November 27, 2009 Author Report Share Posted November 27, 2009 (edited) Your question is not unclear, the solution is quite easy, you should use a property node with the 'Value(signalling)' property, this will activate the event case. However I advise you to take a different framework either use a User Event or a Queued Message Handler or the JKI State Machine toolki. Ton Thanks for the reply. Since I'm quite new in Labview, could you explain a little bit more what to do with the property node? And also can you give me some more info about the other methods you propose? Edited November 27, 2009 by san_gr Quote Link to comment
jgcode Posted November 27, 2009 Report Share Posted November 27, 2009 Thanks for the reply. Since I'm quite new in Labview, could you explain a little bit more what to do with the property node? And also can you give me some more info about the other methods you propose? Programmatically writing to a control, local variable, global variable, datasocket or a value property will not cause the Event Structure to fire a Value Change event. One way to do this programmatically is to use the Value Change (Signalling) property node of a control. This will cause a Value Change event to fire in the Event Structure that has registered for this event. If you search for design patterns you will get a lot of hits e.g. LAVA WIKI NI NI Darren's Nuggets JKI Design patterns help you solve problems and stops you from having to reinvent the wheel. Quote Link to comment
jcarmody Posted November 28, 2009 Report Share Posted November 28, 2009 [...]And also can you give me some more info about the other methods you propose? The first thought I had when reading your original post was to use a User Event. Â These are events similar to Front Panel object events, but you determine the data type and you write code to trigger them wherever you want. Â In your case, you'd trigger it when you get the xFF from the microcontroller and your Event Structure will respond. Here's an example. UsrEvent.vi 1 Quote Link to comment
san_gr Posted November 29, 2009 Author Report Share Posted November 29, 2009 The first thought I had when reading your original post was to use a User Event. These are events similar to Front Panel object events, but you determine the data type and you write code to trigger them wherever you want. In your case, you'd trigger it when you get the xFF from the microcontroller and your Event Structure will respond. Here's an example. I think this is exactly what I need. Thanks. Programmatically writing to a control, local variable, global variable, datasocket or a value property will not cause the Event Structure to fire a Value Change event. One way to do this programmatically is to use the Value Change (Signalling) property node of a control. This will cause a Value Change event to fire in the Event Structure that has registered for this event. To be honest I'm not sure I understood what you are suggesting but I think it's similar to what jcarmody says. Anyway thanks for the links. I will look into them. Quote Link to comment
jgcode Posted November 29, 2009 Report Share Posted November 29, 2009 To be honest I'm not sure I understood what you are suggesting but I think it's similar to what jcarmody says. Anyway thanks for the links. I will look into them. The example attached can fire an event for Control 1 using the control or another event, which makes use of the Value Signaling property node. The counter will increment in the Control 1 Value Change Event case. Pressing either Control 1 or Progammactically Fire Control 1 Event will increment it. So anywhere in your code you can write to this property node to create a Control 1 Value Change Event. It is just another way to programmatically fire an event. It is the same as doing it registering an User Event (as jcarmody has posted) albeit most likely a little easier to start with, but not as flexible. Value Signaling.vi [LabVIEW 8.2] Quote Link to comment
Norm Kirchner Posted November 29, 2009 Report Share Posted November 29, 2009 It is just another way to programmatically fire an event. It is the same as doing it registering an User Event (as jcarmody has posted) albeit most likely a little easier to start with, but not as flexible. Bad bad bad jgcode. Bad! San... Please disregard the any mention of the (signaling) property. This is something that is VASTLY abused and should be avoided at all costs. let me repeat, DON"T USE THE SIGNALING PROPERTY unless no other way of doing it. Newbies use this methodology in excess and end up really regretting it down the line. This tactic is not easily traceable, debuggable or extendable (going N+1) Just look at some of the stock examples that come with LabVIEW for user events and dynamic events. Your effort will pay off 20 times easily in better code. Long story short, if you want reactive code to a user input, utilize an event structure to respond to that action. If you want reactive code to a group or types of controls/indicators look into dynamic event registration If you want code to react to programatically to different parts of programs (without user input) then look into user events. and once again BAD JGCODE! 1 Quote Link to comment
jgcode Posted November 29, 2009 Report Share Posted November 29, 2009 Bad bad bad jgcode. Bad! San... Please disregard the any mention of the (signaling) property. This is something that is VASTLY abused and should be avoided at all costs. let me repeat, DON"T USE THE SIGNALING PROPERTY unless no other way of doing it. Newbies use this methodology in excess and end up really regretting it down the line. This tactic is not easily traceable, debuggable or extendable (going N+1) Just look at some of the stock examples that come with LabVIEW for user events and dynamic events. Your effort will pay off 20 times easily in better code. Long story short, if you want reactive code to a user input, utilize an event structure to respond to that action. If you want reactive code to a group or types of controls/indicators look into dynamic event registration If you want code to react to programatically to different parts of programs (without user input) then look into user events. and once again BAD JGCODE! lol First I totally agree with you that this can be bad as in using globals is bad. But everything has a place, and everyone is at different programming levels and knowledge levels, so I think depending on a per use case it needs this needs to be judged. So taking the topic into perspective: Since I'm quite new in Labview You think someone who has openly stated they are new to LabVIEW is going write beautiful code, first time, off the bat? Understanding dynamic events is hardly a basic level subject. Especially given they are unfamiliar with design patterns (also stated). I am by no means having a go here, just establishing an estimated LabVIEW experience level based on the facts posted. So if someone starting out has a basic application, and the use of Val(Sign) property works and gets the job done, but they learn stuff along the way - is that such a bad thing? I never stated to abuse it like a red headed step child, I stated a method that could achieve the result outlined in the original post. Additionally I am of the opinion that it is not detrimental that somebody has knowledge of how the Value Signaling works. If they do not know it exists, or do not understand how it works, then how are they to know why its bad? Programming is a journey (well at least for me), it is about finding stuff out, trying different things (can always skin a cat different ways). So telling someone to disregard the Val(Sign) property means discouragement from learning something and from trying it out for themselves. This in my opinion, is counter-productive to that journey. Bad, bad, bad Norm. 1 Quote Link to comment
Popular Post Norm Kirchner Posted November 29, 2009 Popular Post Report Share Posted November 29, 2009 First I totally agree with you that this can be bad as in using globals is bad. everyone is at different programming levels and knowledge levels, You think someone who has openly stated they are new to LabVIEW is going write beautiful code, Understanding dynamic events is hardly a basic level subject. So if someone starting out has a basic application, and the use of Val(Sign) property works and gets the job done, is that such a bad thing? I never stated to abuse it it is not detrimental that somebody has knowledge. If they do not know it exists, or do not understand how it works, then how are they to know why its bad? Programming is a journey. So telling someone to disregard the Val(Sign) property means discouragement from learning something I suppose I'll clarify my point for just a sec, then I'll try to follow my own points (about to be given) and provide alternatives. I think using (not even abusing) the Val(signaling) property is far far worse than globals depending on usage. Hence the fervor. I don't expect pretty code out of the gate but I don't know how to stop a newbie from adopting poor practices out of the gate other than striking the fear of god into them. Agreed, using dynamic events 'as truly dynamic events' is not a beginner topic, but I believe the use of 'user events' are beginner material which only requires knowledge of the mechanics of wiring them up. and summing up those last few points: I think that a smarter person than I would not need the 'fear-o-god' tactic to discourage poor techniques. Rather it would be much more classy and eloquent to give knowledge to them through some simple example programs demonstrating the bad aspects and demonstrations of better ways to do it. Now onto my attempt at eloquence: Jim Carmody did a great job with exactly what I think San was gunning for so I'll try not to replicate that First on some of the dangers of using the Val(signaling) Some simple programs are created that are fully reactive (waiting for some event to happen) and you will see this as just an event structure in a while loop. <a href="http://content.screencast.com/users/NJKirchner/folders/Jing/media/8689b74b-ac72-44c8-952e-80c386e03c21/2009-11-29_1536.png"><img'>http://content.screencast.com/users/NJKirchner/folders/Jing/media/8689b74b-ac72-44c8-952e-80c386e03c21/2009-11-29_1536.png"><img class="embeddedObject" src="http://content.screencast.com/users/NJKirchner/folders/Jing/media/8689b74b-ac72-44c8-952e-80c386e03c21/2009-11-29_1536.png" width="448" height="226" border="0" /></a> And depending on the scope of the code, this can get the job done just fine and avoid extra coding that may never be utilized. But the problem, and this sounds much closer to what San was looking at, is what happens when you now need to invoke the code within this state without the user hitting a button? By default, if the user doesn't know any better, they'll use the Val(Signaling) property. This is typically because it will require almost no extra code to be written other than dropping that property node. Well this starts to snowball into a bigger issue when someone decides that they just don't want to execute that one event state, but rather I need 4 states executed and I want that state to always be the second of the 4. What typically happens, is that the end user just starts stringing together multiple Val(signaling) properties for multiple controls to call multiple event states. This is particularly bad because there is no guarantee that as you string together Val(signaling) properties that they'll execute in that order, so you've just introduced potential bad logic in your vi. Now it gets even trickier if you like to use property nodes all over you code because if you need to better understand the flow of the program, how do you know who and what is controlling the state firing? Search for Val(signaling): you get all usages of that property (fail). Search for all property nodes of a given control: you now find every property of a control and you only find the property nodes that are directly linked to that control and you miss any non-linked property node. <a href="http://content.screencast.com/users/NJKirchner/folders/Jing/media/54b79210-0b47-42d6-9770-4be1f36bbe13/2009-11-29_1555.png"><img'>http://content.screencast.com/users/NJKirchner/folders/Jing/media/54b79210-0b47-42d6-9770-4be1f36bbe13/2009-11-29_1555.png"><img class="embeddedObject" src="http://content.screencast.com/users/NJKirchner/folders/Jing/media/54b79210-0b47-42d6-9770-4be1f36bbe13/2009-11-29_1555.png" width="437" height="142" border="0" /></a> And just to re-itterate. Don't underestimate the need to understand the flow of a program. You will someday need to re-learn what you wrote. Someone's LAVA tagline is perfect for this "Imagine the next person to work with your code is a deranged psychopath and knows where you live" So now onto some alternatives and notes about the Val(Signaling) property. Its intent in life is to provide that 'if all else wont work' kind of functionality to the LV language. An example of this is when using the data terminal of an event case. In this case you want that data on the terminal and the only way to programatically fire that event and still have that data is through the Val(signaling) property <a href="http://content.screencast.com/users/NJKirchner/folders/Jing/media/41648ccd-13e7-4e07-9cce-b867b4dc6821/2009-11-29_1605.png"><img'>http://content.screencast.com/users/NJKirchner/folders/Jing/media/41648ccd-13e7-4e07-9cce-b867b4dc6821/2009-11-29_1605.png"><img class="embeddedObject" src="http://content.screencast.com/users/NJKirchner/folders/Jing/media/41648ccd-13e7-4e07-9cce-b867b4dc6821/2009-11-29_1605.png" width="448" height="223" border="0" /></a> Now the alternative or smarter architecture associated with this, is to have the event cause a reaction in some other piece of code somewhere else that you have more control over than an event structure. This is where a solid event driven producer consumer design pattern comes in handy. I won't go into the architecture of this here but what this does allow you to do is have the code to be executed in a place that can be easily invoked programatically or interactively. Do the amount of wires increase? yes. Does the architecture increase in complexity? yes. Do you have a much more flexible and debuggable piece of code for just a little more effort? No question about it absolutely. So for the how-to-do-it portion of the code. San, It sounds like you are monitoring your code for the 0xFF Byte and want some other part of code to react when this happens. The code that Jim sent is about spot on and the only other thing that you'll need to do is share the reference to that newly created user event around your codebase. <a href="http://content.screencast.com/users/NJKirchner/folders/Jing/media/6f18fd2d-c4a3-4e6b-9c38-c62bac86edf8/2009-11-29_1617.png"><img'>http://content.screencast.com/users/NJKirchner/folders/Jing/media/6f18fd2d-c4a3-4e6b-9c38-c62bac86edf8/2009-11-29_1617.png"><img class="embeddedObject" src="http://content.screencast.com/users/NJKirchner/folders/Jing/media/6f18fd2d-c4a3-4e6b-9c38-c62bac86edf8/2009-11-29_1617.png" width="316" height="265" border="0" /></a> The part of code that needs to fire the event, will use the 'Generate User Event' vi <a href="http://content.screencast.com/users/NJKirchner/folders/Jing/media/8a8cf0e9-cc0d-445d-acf9-b9483e37fbcf/2009-11-29_1619.png"><img'>http://content.screencast.com/users/NJKirchner/folders/Jing/media/8a8cf0e9-cc0d-445d-acf9-b9483e37fbcf/2009-11-29_1619.png"><img class="embeddedObject" src="http://content.screencast.com/users/NJKirchner/folders/Jing/media/8a8cf0e9-cc0d-445d-acf9-b9483e37fbcf/2009-11-29_1619.png" width="235" height="488" border="0" /></a> And all parts of the code that need to respond to that event need to dynamically register for that event and then have an event case that registers for it. <object width="810" height="612"> <param name="movie" value="http://content.screencast.com/users/NJKirchner/folders/Jing/media/e17f4a92-a2a5-428a-b981-2393f28ebc2a/jingh264player.swf"></param>'>http://content.screencast.com/users/NJKirchner/folders/Jing/media/e17f4a92-a2a5-428a-b981-2393f28ebc2a/jingh264player.swf"></param> <param name="quality" value="high"></param> <param name="bgcolor" value="#FFFFFF"></param> <param name="flashVars" value="thumb=http://content.screencast.com/users/NJKirchner/folders/Jing/media/e17f4a92-a2a5-428a-b981-2393f28ebc2a/FirstFrame.jpg&containerwidth=810&containerheight=612&content=http://content.screencast.com/users/NJKirchner/folders/Jing/media/e17f4a92-a2a5-428a-b981-2393f28ebc2a/2009-11-29_1624.mp4"></param> <param name="allowFullScreen" value="true"></param> <param name="scale" value="showall"></param> <param name="allowScriptAccess" value="always"></param> <param name="base" value="http://content.screencast.com/users/NJKirchner/folders/Jing/media/e17f4a92-a2a5-428a-b981-2393f28ebc2a/"></param>'>http://content.screencast.com/users/NJKirchner/folders/Jing/media/e17f4a92-a2a5-428a-b981-2393f28ebc2a/"></param> <embed src="http://content.screencast.com/users/NJKirchner/folders/Jing/media/e17f4a92-a2a5-428a-b981-2393f28ebc2a/jingh264player.swf" quality="high" bgcolor="#FFFFFF" width="810" height="612" type="application/x-shockwave-flash" allowScriptAccess="always" flashVars="thumb=http://content.screencast.com/users/NJKirchner/folders/Jing/media/e17f4a92-a2a5-428a-b981-2393f28ebc2a/FirstFrame.jpg&containerwidth=810&containerheight=612&content=http://content.screencast.com/users/NJKirchner/folders/Jing/media/e17f4a92-a2a5-428a-b981-2393f28ebc2a/2009-11-29_1624.mp4" allowFullScreen="true" base="http://content.screencast.com/users/NJKirchner/folders/Jing/media/e17f4a92-a2a5-428a-b981-2393f28ebc2a/" scale="showall"></embed> </object> 4 Quote Link to comment
jcarmody Posted November 29, 2009 Report Share Posted November 29, 2009 [...]Well this starts to snowball into a bigger issue when someone decides that they just don't want to execute that one event state, but rather I need 4 states executed and I want that state to always be the second of the 4. What typically happens, is that the end user just starts stringing together multiple Val(signaling) properties for multiple controls to call multiple event states. This is particularly bad because there is no guarantee that as you string together Val(signaling) properties that they'll execute in that order, so you've just introduced potential bad logic in your vi. I did not know that. Â Thanks. Quote Link to comment
jgcode Posted November 30, 2009 Report Share Posted November 30, 2009 and summing up those last few points: I think that a smarter person than I would not need the 'fear-o-god' tactic to discourage poor techniques. Rather it would be much more classy and eloquent to give knowledge to them through some simple example programs demonstrating the bad aspects and demonstrations of better ways to do it. Agreed. While its nice, in this case, you have taken the time to go into detail, there is always more in-depth knowledge available out there, and can't you feed everyone. That is why I posted links to design patterns. I was also answering one of the topic starter's original questions: Thanks for the reply. Since I'm quite new in Labview, could you explain a little bit more what to do with the property node? And also can you give me some more info about the other methods you propose? And I did post this disclaimer: It is just another way to programmatically fire an event. It is the same as doing it registering an User Event (as jcarmody has posted) albeit most likely a little easier to start with, but not as flexible. Anyways, because they are not a basic topic, I am sure you can make a hell of a mess using dynamic events, the user could easily: E.g. Pass the reference deeply into their app (like your control ref example) and fire them from anywhere in an application making it difficult to debug. As this would be down to having good programming style (or not). I actually can't see using a user event or Val(Sign) is any different is this case (aside from the point you mentioned of asynchronous firing of sequential Val(Sign) nodes)? Branching the Event Registration Refnum and passing it into two Event Structures, causing missed events (when you should have branched the User Event Refnum and creating a second Event Registration Refnum). Not understand when events go into memory - statically registered events go into memory when the top level VI goes into the reserved state and are removed when the top level VI finishes executing. Dynamic events have the ability to go into and out of memory meaning the user can control this, meaning there is more that could go wrong as they have the potential to destroy the queue and registered event. etc... Additionally if an Event Case takes a longer time then human reaction time to complete, handling the event in the User Interface Event Structure may cause the front panel to lock up. Regardless of whether front panel locking is disabled (only for notify events), the UI will still be unresponsive. A PC-(Events) design pattern or similar would be required, or handling setting the cursor. Whilst everyone has an opinion based on their experiences etc... and yours is that you obviously detest the Val(Sign) to point where using one is very bad which is cool, mine include: Everything has a place, I am not saying I use technique all throughout my code (in fact I rarely use it) - but it does have a use case, saying originally to never using it, IMHO is not that helpful. You need to walk before you crawl - if you don't understand firing off an event, or basic design patterns, I am sure the use of a Val(Sign) property will not make or break your code. And while it is definitely less flexible, it may be much, much less complex and get the job done (especially if the software's lifespan is short (test stub or prototyping something), a high quality level is not a requirement, the user is completing an example project (e.g. assignment)... Knowledge will increase through ones own trial and error, backed up an intermediate ability to search for resources and good comprehension skills of those resources (I find that this is a cycle as I get better at one, I get better at the other etc...). All in all nice posts, but I think bashing the Val(Sign) is a little harsh. My 2 cents Quote Link to comment
Daklu Posted November 30, 2009 Report Share Posted November 30, 2009 Well this starts to snowball into a bigger issue when someone decides that they just don't want to execute that one event state, but rather I need 4 states executed and I want that state to always be the second of the 4. What typically happens, is that the end user just starts stringing together multiple Val(signaling) properties for multiple controls to call multiple event states. This is particularly bad because there is no guarantee that as you string together Val(signaling) properties that they'll execute in that order, so you've just introduced potential bad logic in your vi. This is new information for me as well. Can you expand on it? Under what circumstances does an event queue not execute events in the order they are received? Quote Link to comment
san_gr Posted November 30, 2009 Author Report Share Posted November 30, 2009 (edited) I don't know what you say about Norm or jgcode but i tried what these guys suggested and it worked like a charm. It was exactly what i was looking for. Thanks again guys Edited November 30, 2009 by san_gr Quote Link to comment
san_gr Posted December 1, 2009 Author Report Share Posted December 1, 2009 (edited) I don't know what you say about Norm or jgcode but... :oops: I meant jcarmody. Sorry dude! Edited December 1, 2009 by san_gr Quote Link to comment
Yair Posted December 1, 2009 Report Share Posted December 1, 2009 This is new information for me as well. Can you expand on it? Under what circumstances does an event queue not execute events in the order they are received? I know that this can happen if you have both dynamic events and static events fire at the same time because they go into two queues and the order is only determined by the millisecond timer. See here. As far as I know, this should NOT apply to val(sgnl) events you string together. I believe they should execute in order. 2 Quote Link to comment
Norm Kirchner Posted December 1, 2009 Report Share Posted December 1, 2009 I know that this can happen if you have both dynamic events and static events fire at the same time because they go into two queues and the order is only determined by the millisecond timer. See here. As far as I know, this should NOT apply to val(sgnl) events you string together. I believe they should execute in order. I say this from a standpoint of that I have never heard of anything that ensures that they will be ordered properly. There is most likely a high likelihood that they will, but this only highlights that people write programs that assume this. If AQ or someone in R&D pipes up and says that it is ensured, then I'll fully retract that. But I will never recommend that anyone write a program that depends on having multiple Val(signl) strung together to execute the events in that order for all those reasons above. San, As a point of information, what is your skill/experience level in LV? 1 Quote Link to comment
san_gr Posted December 1, 2009 Author Report Share Posted December 1, 2009 San, As a point of information, what is your skill/experience level in LV? Well, I had some courses 5 years ago but we only did some while loops with a timer or a button and in every press (or tick) it was adding +1 to an indicator. So, basically this is the first time I'm actually using labview. But I have some basic knowledge in C programming and although LV is very different, I can pretty much understand how most of the things work. The thing is that I don't know any LV terminology (e.g. Val(signl), etc) or what kind of blocks are there and where to find them. But, for a first project I'm pretty happy with myself. See for yourself :D Elevator.zip Quote Link to comment
Daklu Posted December 2, 2009 Report Share Posted December 2, 2009 Thanks for the link Yair and the explanation Norm. I'll have to retrain my brain not to think of an "event queue" working behind the scenes as that leads to an expectation of ordered execution. Quote Link to comment
Yair Posted December 2, 2009 Report Share Posted December 2, 2009 I'll have to retrain my brain not to think of an "event queue" working behind the scenes as that leads to an expectation of ordered execution. I agree from a defensive programming point of view, but I actually consider the issue shown in the other thread to be a bug. I can see the technical reasons for why it was implemented as such, but as a user of the event structure, I most definitely expect the event cases to execute in the order in which the events were fired. I think this expectation is so basic and obvious that it doesn't even need to be documented. However, I can see some other potential cases where events would not be executed in the order in which they were fired (e.g. if an event structure needs to wait on a filter event, maybe it skips to the next events in its queue?). Quote Link to comment
jgcode Posted December 3, 2009 Report Share Posted December 3, 2009 I know that this can happen if you have both dynamic events and static events fire at the same time because they go into two queues and the order is only determined by the millisecond timer. See here. As far as I know, this should NOT apply to val(sgnl) events you string together. I believe they should execute in order. Thanks for posting the link Quote Link to comment
Ton Plomp Posted December 5, 2009 Report Share Posted December 5, 2009 Bad bad bad jgcode. Bad! This post is a thank-you to Norm. I owed him a beer/Value Signalling bashing. I created a VI that traverses a VI for a list of given properties (per default value (signalling)) and shows a tree with the VIs and instances where the given property is used. Double click to locate the given property: Ton Find Properties.llb Quote Link to comment
shoneill Posted December 5, 2009 Report Share Posted December 5, 2009 This is new information for me as well. Can you expand on it? Under what circumstances does an event queue not execute events in the order they are received? Same thing happens with XControls also. See HERE. Look past the queueing issues and it the Event queue gets all mixed up in execution order. Shane. Quote Link to comment
jgcode Posted December 5, 2009 Report Share Posted December 5, 2009 I owed him a beer/Value Signalling bashing. ...but you like to use them in your code Quote Link to comment
jgcode Posted July 19, 2010 Report Share Posted July 19, 2010 Hate to raise an old post... NI even used a Val(Sgnl) PN to cover a requirement in their CLA solution example ! Quote Link to comment
Recommended Posts
Join the conversation
You can post now and register later. If you have an account, sign in now to post with your account.