Strange "Collection was modified after the enumerator was instantiated" exception - c#

Perhaps someone can point me in the correct direction, because I'm completely stumped on this.
I have a function that simply prints out a LinkedList of classes:
LinkedList<Component> components = new LinkedList<Component>();
...
private void PrintComponentList()
{
Console.WriteLine("---Component List: " + components.Count + " entries---");
foreach (Component c in components)
{
Console.WriteLine(c);
}
Console.WriteLine("------");
}
The Component object actually has a custom ToString() call as such:
int Id;
...
public override String ToString()
{
return GetType() + ": " + Id;
}
This function typically works fine - however I've run into the issue that when it builds to about 30 or so entries in the list, the PrintcomplentList foreach statement comes back with an InvalidOperationException: Collection was modified after the enumerator was instantiated.
Now as you can see I'm not modifying the code within the for loop, and I haven't explicitly created any threads, although this is within an XNA environment (if it matters). It should be noted that the printout is frequent enough that the Console output is slowing down the program as a whole.
I'm completely stumped, has anyone else out there run into this?

I suspect the place to start looking will be at any places where you manipulate the list - i.e. insert/remove/re-assign items. My suspicion is that there will be a callback/even-handler somewhere that is getting fired asynchronously (perhaps as part of the XNA paint etc loops), and which is editing the list - essentially causing this problem as a race condition.
To check if this is the case, put some debug/trace output around the places that manipulate the list, and see if it ever (and in particular, just before the exception) runs the manipulation code at the same time as your console output:
private void SomeCallback()
{
Console.WriteLine("---Adding foo"); // temp investigation code; remove
components.AddLast(foo);
Console.WriteLine("---Added foo"); // temp investigation code; remove
}
Unfortunately, such things are often a pain to debug, as changing the code to investigate it often changes the problem (a Heisenbug).
One answer would be to synchronize access; i.e. in all the places that edit the list, use a lock around the complete operation:
LinkedList<Component> components = new LinkedList<Component>();
readonly object syncLock = new object();
...
private void PrintComponentList()
{
lock(syncLock)
{ // take lock before first use (.Count), covering the foreach
Console.WriteLine("---Component List: " + components.Count
+ " entries---");
foreach (Component c in components)
{
Console.WriteLine(c);
}
Console.WriteLine("------");
} // release lock
}
and in your callback (or whatever)
private void SomeCallback()
{
lock(syncLock)
{
components.AddLast(foo);
}
}
In particular, a "complete operation" might include:
check the count and foreach/for
check for existance and insert/remove
etc
(i.e. not the individual/discrete operations - but units of work)

Instead of foreach, I use while( collection.count >0) then use collection[i].

I don't know if this is relevant to the OP but I had the same error and found this thread during a google search. I was able to solve it by adding a break after removing an element in the loop.
foreach( Weapon activeWeapon in activeWeapons ){
if (activeWeapon.position.Z < activeWeapon.range)
{
activeWeapons.Remove(activeWeapon);
break; // Fixes error
}
else
{
activeWeapon.position += activeWeapon.velocity;
}
}
}
If you leave out the break, you will get the error "InvalidOperationException: Collection was modified after the enumerator was instantiated."

Using Break could be a way but it may impact your series of operation.
What I do in that case in simply convert the foreach to traditional for loop
for(i=0; i < List.count; i++)
{
List.Remove();
i--;
}
This works without any issues.

Related

Is there a way to await a flag change in a function?

I've attempted to make a simple step mode for an algorithm I'm running, and here is how it looks like:
public async Task<bool> AStarAlgorithmAsync(PFSquare curr = null)
{
// some algorithm code here
foreach(var square in Sorroundings)
{
if (SteppedMode)
{
await Task.Run(Pause);
}
if (await AStarAlgorithmAsync(square))
{
return true;
}
}
}
In my application, I have a Boolean called SteppedMode that decides if the algorithm should run one iteration per click event.
Pause() looks like this:
private void Pause()
{
while (!ContinueStep) { }
ContinueStep = false;
return;
}
And in another part of my (GUI) application I have an event which sets the boolean ContinueStep to true which in theory should end the while loop and continue the algorithm function. Currently this bit of code locks my GUI thread up and I'm almost certain there is a better way to do this.
I'm trying to get my algorithm function to run one iteration, wait for a click from the user and only then continue running the algorithm. Is there an easier and cleaner way to do this?
(This is a GUI application, not a console application.)
Your property is moonlighting as a method.
It makes no sense to set a property, to then have that property revert back to its original state immediately. As a consumer, I would be majorly confused by that behavior. Think about this code:
var myObj = new MyObject();
myObj.MyBoolean = true;
Console.WriteLine(myObj.MyBoolean); // FALSE!?
It just doesn't make sense.
The only effect you want to trigger by setting this property is to execute some code. That's exactly what methods are supposed to be used for:
public void ContinueStep()
{
Console.WriteLine("I did some work");
}
So instead of this:
myObj.ContinueStep = true;
you should be doing this:
myObject.ContinueStep();
This doesn't lock up your UI thread, while also being a lot more sensical to your consumer. The method suggests that some action will be taken (which may or may not lead to state changes in the object - that's a contextual expectation).
Infinite recursion
As an aside; based on your code, AStarAlgorithmAsync is a recursive function, and seemingly infinitely so. There doesn't seem to be an ending condition.
Every recursive level will interate over the first surrounding and then trigger the next level, which again will interate over the first surrounding and then trigger the next level, which again ...
That can't be right, but it's unclear to me how to fix it as the bigger picture is not explained in your question
A simple implementation
What I'm trying to do is get my algorithm function to run one iteration, wait for a click from the user and only then continue running the algorithm, is there an easier and cleaner way to do this?
A simple example of such a thing:
private int _index = 0;
private List<object> _myList = ...; // assume this list contains some elements
public void ProcessNextObject()
{
if(_index < _myList.Length)
{
Process(_myList[_index]);
_index++;
}
}
private void Process(object o)
{
Console.WriteLine("Processing this object!");
}
You can then hook up your click event to call ProcessNextObject().
Note that in this example, the list is processed once and cannot be processed again. By manipulating the index value, you can change that behavior as you like.

Multiple Timers treating List at high speed causes issue

I'm writing a C# library that needs to treat a List at high speed via multiple Timers.
I ran into very erratic error, where I try to remove an element that I know for sure is contained into the List but the program returns the following error :
System.IndexOutOfRangeException : 'index was outside the bounds of the array.'
I've made a simple example to reproduce this behaviour. Because of that issue's randomness, I've pushed hard on List operations so it throws the error right away. So this example is necessary "weird".
I've made a public repo on here : Issue Example Repo
Basically, here's what I'm dealing with:
list = new List<DummyElement>();
for (int i = 0; i < 1000; i++)
{
Timer addTimer = new Timer(0.01f);
addTimer.Start();
addTimer.Elapsed += AddItem;
Timer removeTimer = new Timer(0.01f);
removeTimer.Start();
removeTimer.Elapsed += RemoveItem;
}
void AddItem(object source, ElapsedEventArgs e)
{
list.Add(new DummyElement());
}
void RemoveItem(object source, ElapsedEventArgs e)
{
int listCount = list.Count;
if (listCount > 0) // This condition is successfully passed, so there is at least one element on the list
{
list.RemoveAt(0); // This line throw an IndexOutOfRangeException error
}
}
I believe it is a thread related issue, as if the list count was changing AFTER the condition was successfully passed.
I know nothing about thread, how can I deal with this issue?
In the For loop that goes upto 1000 - you are creating about 1000 Timers that add an item into list and 1000 timers that remove first item.
Since you haven't used any synchronization here's what happens:- Say there is 1 item in List and 2 RemoveItems are executing. both see listCount > 0 as True then one of them goes ahead and removes the Item at 0th Index while the other gets an Exception cause there is no item to remove now.
Now I cant suggest a solution to this by just looking at the code. I also need to understand the intent.
This is a Text Book Producer Consumer problem so the Text book advice here is using Lock construct:
Assume you have a class member like:
private object _lockMe = new object();
void RemoveItem(object source, ElapsedEventArgs e)
{
lock(_lockMe)
{
int listCount = list.Count;
if (listCount > 0) // This condition is successfully passed, so there is at least one element on the list
{
list.RemoveAt(0); // This line throw an IndexOutOfRangeException error
}
}
}

MessageBox and while loop C#

I'm modifying existing C# code in order to pilote a piston. Every 30ms, I have a direct feedback of the position of this piston, through an event. The value is stored in a global variable I use to get the current position of the piston.
What I'm trying to achieve: for a given distance input (A->C), I want the piston to travel at full speed for 95% of the distance (A->B), and then slower for the remaining 5% (B->C).
I have access to a command that defines the speed and the destination of the piston : pos(velocity, destination).
However, if I write that code:
pos(fullSpeed,B);
pos(reducedSpeed, C);
the piston directly goes from fullSpeed to reducedSpeed
I tried to use a while loop to compare the current position of the piston with the goal destination, however, upon entering the while loop, the variable storing the piston position does not update anymore.
However, I noticed that by throwing a MessageBox in between, the position value keeps on getting updated, and I can simply click "ok" to launch the second command.
pos(fullSpeed,B);
MessageBox.show("Wait");
pos(reducedSpeed, C);
I would like to know why the "while" loop stops the update of the position variable but the MessageBox does not. I mean, as long as I don't click the "ok" button, the box is here preventing me from doing anything, which for me ressembles a while loop behaviour. Is there another way for me to do this instead of the MessageBox ?
I have little to no knowledge when it comes to C# and no support. I have tried to look in the documentation, but I did not find an answer (I have probably missed it). Any lead is more than welcome.
EDIT: I have no documentation for that code, and it is barely commented. Here is what I gathered (really hope it helps):
To move the piston, taht function is called:
MyEdc.Move.Pos(control, speed, destination, ref MyTan);
control simply define what we pilote (a distance or a load, it is an enum), and I have no idea what MyTan does. Only thing I know is that the MyEdc.Move.Pos returns an error code.
If I look at the definition of "pos", I am redirected to class
public DoPEmove Move;
containing among other things:
public DoPE.ERR Pos(DoPE.CTRL MoveCtrl, double Speed, double Destination, ref short Tan);
DoPE.ERR is also an type enum. However, I cannot reach the definition of a function named "Pos". Coud it be within the .dll included ?
The following is the code that allows me to access the position of the piston (without the global variables):
private int OnData(ref DoPE.OnData Data, object Parameter)
{
if (Data.DoPError == DoPE.ERR.NOERROR)
{
DoPE.Data Sample = Data.Data;
Int32 Time = Environment.TickCount;
if ((Time - LastTime) >= 300 /*ms*/)
{
LastTime = Time;
string text;
text = String.Format("{0}", Sample.Time.ToString("0.000"));
guiTime.Text = text;
text = String.Format("{0}", Sample.Sensor[(int)DoPE.SENSOR.SENSOR_S].ToString("0.000"));
guiPosition.Text = text;
text = String.Format("{0}", Sample.Sensor[(int)DoPE.SENSOR.SENSOR_F].ToString("0.000"));
guiLoad.Text = text;
text = String.Format("{0}", Sample.Sensor[(int)DoPE.SENSOR.SENSOR_E].ToString("0.000"));
guiExtension.Text = text;
}
}
return 0;
}
Which is called using
MyEdc.Eh.OnDataHdlr += new DoPE.OnDataHdlr(OnData);
I realise how little I know on how the soft operates, and how frustrating this is for you. If you think this is a lost cause, no problem, I'll try Timothy Jannace solution, and if it does not help me, I'll stick with the MessageBox solution. I just wanted to know why the MessageBox allowed me to sort of achieve my objectif, but the while loop did not, and how to use it in my advantage here.
I tried to use a while loop to compare the current position of the
piston with the goal destination, however, upon entering the while
loop, the variable storing the piston position does not update
anymore.
While you are in the while loop, your app can no longer receive and process the feedback event.
One possible solution would be to use async/await like this:
private const int fullSpeed = 1;
private const int reducedSpeed = 2;
private int currentPistonPositon = 0; // global var updated by event as you described
private async void button1_Click(object sender, EventArgs e)
{
int B = 50;
int C = 75;
pos(fullSpeed, B);
await Task.Run(() =>
{ // pick one below?
// assumes that "B" and "currentPistonPosition" can actually be EXACTLY the same value
while (currentPistonPositon != B)
{
System.Threading.Thread.Sleep(25);
}
// if this isn't the case, then perhaps when it reaches a certain threshold distance?
while (Math.Abs(currentPistonPositon - B) > 0.10)
{
System.Threading.Thread.Sleep(25);
}
});
pos(reducedSpeed, C);
}
Note the button1_Click method signature has been marked with async. The code will wait for the while loop inside the task to complete while still processing event messages because of the await. Only then will it move on to the second pos() call.
Thank you for your answer ! It works like a charm ! (good catch on the
EXACT value). I learnt a lot, and I am sure the async/await combo is
going to be very usefull in the future ! – MaximeS
If that worked well, then you might want to consider refactoring the code and making your own "goto position" method like this:
private void button1_Click(object sender, EventArgs e)
{
int B = 50;
int C = 75;
GotoPosition(fullSpeed, B);
GotoPosition(reducedSpeed, C);
}
private async void GotoPosition(int speed, int position)
{
pos(speed, position);
await Task.Run(() =>
{
while (Math.Abs(currentPistonPositon - position) > 0.10)
{
System.Threading.Thread.Sleep(25);
}
});
}
Readability would be greatly improved.
You could even get fancier and introduce a timeout concept into the while loop. Now your code could do something like below:
private void button1_Click(object sender, EventArgs e)
{
int B = 50;
int C = 75;
if (GotoPosition(fullSpeed, B, TimeSpan.FromMilliseconds(750)).Result)
{
if (GotoPosition(reducedSpeed, C, TimeSpan.FromMilliseconds(1500)).Result)
{
// ... we successfully went to B at fullSpeed, then to C at reducedSpeed ...
}
else
{
MessageBox.Show("Piston Timed Out");
}
}
else
{
MessageBox.Show("Piston Timed Out");
}
}
private async Task<bool> GotoPosition(int speed, int position, TimeSpan timeOut)
{
pos(speed, position); // call the async API
// wait for the position to be reached, or the timeout to occur
bool success = true; // assume we have succeeded until proven otherwise
DateTime dt = DateTime.Now.Add(timeOut); // set our timeout DateTime in the future
await Task.Run(() =>
{
System.Threading.Thread.Sleep(50); // give the piston a chance to update maybe once before checking?
while (Math.Abs(currentPistonPositon - position) > 0.10) // see if the piston has reached our target position
{
if (DateTime.Now > dt) // did we move past our timeout DateTime?
{
success = false;
break;
}
System.Threading.Thread.Sleep(25); // very small sleep to reduce CPU usage
}
});
return success;
}
If you're using events you are probably having concurrency issues. Especially with events being raised every 30ms!
A very simple way to handle concurrency is to use a lock object to prevent different threads from using contested resources simultaneously:
class MyEventHandler
{
private object _lockObject;
MyEventHandler()
{
_lockObject = new object();
}
public int MyContestedResource { get; }
public void HandleEvent( object sender, MyEvent event )
{
lock ( _lockObject )
{
// do stuff with event here
MyContestedResource++;
}
}
}
Keep in mind that is very simple and by no means perfect in every scenario. If you provide more information about how the events are raised and what you're doing with them people will be able to provide more help.
EDIT:
Using that signature you posted for the Pos method I was able to find documentation on the library you are using: https://www.academia.edu/24938060/Do_PE
The reason you only see the method signature when you goto definition is because the library has been compiled into a dll. Actually, it probably wouldn't be that useful to see the code anyway because it looks like the library is a C# wrapper around native (c or c++) code.
Anyways, I hope the documentation is helpful to you. If you look at page 20 there are some pointers on doing movement. This is going to be a challenge for a new programmer but you can do it. I would suggest you avoid using the event handler to drive your logic and instead stick with using the synchronous versions of commands. Using the synchronous commands your code should operate the same way it reads.
I believe what you'll want to do is add a call to:
Application.DoEvents();
This will allow your application to process posted messages (events), which will allow that global variable to be updated.
I just wanted to know why the MessageBox allowed me to sort of achieve my objectif, but the while loop did not, and how to use it in my advantage here.
The reason that works is because you're giving the WndProc a chance to process events which have been sent to the application. It's not an intended feature of that call to MessageBox.Show();, but it is a consequence. You can do the same thing with a call to Application.DoEvents(); without the interruption of the message box.

Multi-threading problem when checking the list Count property

I have List newJobs. Some threads add items to that list and other thread removes items from it, if it's not empty. I have ManualResetEvent newJobEvent which is set when items are added to the list, and reset when items are removed from it:
Adding items to the list is performed in the following way:
lock(syncLock){
newJobs.Add(job);
}
newJobEvent.Set();
Jobs removal is performed in the following way:
if (newJobs.Count==0)
newJobEvent.WaitOne();
lock(syncLock){
job = newJobs.First();
newJobs.Remove(job);
/*do some processing*/
}
newJobEvent.Reset();
When the line
job=newJobs.First()
is executed I sometimes get an exception that the list is empty. I guess that the check:
if (newJobs.Count==0)
newJobEvent.WaitOne();
should also be in the lock statement but I'm afraid of deadlocks on the line newJobEvent.WaitOne();
How can I solve it?
Many thanks and sorry for the long post!
You are right. Calling WaitOne inside a lock could lead to a deadlock. And the check to see if the list is empty needs to be done inside the lock otherwise there could be a race with another thread trying to remove an item. Now, your code looks suspiciously like the producer-consumer pattern which is usually implemented with a blocking queue. If you are using .NET 4.0 then you can take advantage of the BlockingCollection class.
However, let me go over a couple of ways you can do it youself. The first uses a List and a ManualResetEvent to demonstrate how this could be done using the data structures in your question. Notice the use of a while loop in the Take method.
public class BlockingJobsCollection
{
private List<Job> m_List = new List<Job>();
private ManualResetEvent m_Signal = new ManualResetEvent(false);
public void Add(Job item)
{
lock (m_List)
{
m_List.Add(item);
m_Signal.Set();
}
}
public Job Take()
{
while (true)
{
lock (m_List)
{
if (m_List.Count > 0)
{
Job item = m_List.First();
m_List.Remove(item);
if (m_List.Count == 0)
{
m_Signal.Reset();
}
return item;
}
}
m_Signal.WaitOne();
}
}
}
But this not how I would do it. I would go with the simplier solution below with uses Monitor.Wait and Monitor.Pulse. Monitor.Wait is useful because it can be called inside a lock. In fact, it is suppose to be done that way.
public class BlockingJobsCollection
{
private Queue<Job> m_Queue = new Queue<Job>();
public void Add(Job item)
{
lock (m_Queue)
{
m_Queue.Enqueue(item);
Monitor.Pulse(m_Queue);
}
}
public Job Take()
{
lock (m_Queue)
{
while (m_Queue.Count == 0)
{
Monitor.Wait(m_Queue);
}
return m_Queue.Dequeue();
}
}
}
Not answering your question, but if you are using .NET framework 4, you can use the new ConcurrentQueue which does all the locking for you.
Regarding your question:
One scenario that I can think of causing such a problem is the following:
The insertion thread enters the lock, calls newJob.Add, leaves the lock.
Context switch to the removal thread. It checks for emptyness, sees an item, enters the locked area, removes the item, resets the event - which hasn't even been set yet.
Context switch back to the insertion thread, the event is set.
Context switch back to the removal thread. It checks for emptyness, sees no items, waits for the event - which is already set, trys to get the first item... Bang!
Set and reset the event inside the lock and you should be fine.
I don't see why object removal in case of zero objects should wait for one to be added and then remove it. It looks to be being against logic.

Thread-safe use of a singleton's members

I have a C# singleton class that multiple classes use. Is access through Instance to the Toggle() method thread-safe? If yes, by what assumptions, rules, etc. If no, why and how can I fix it?
public class MyClass
{
private static readonly MyClass instance = new MyClass();
public static MyClass Instance
{
get { return instance; }
}
private int value = 0;
public int Toggle()
{
if(value == 0)
{
value = 1;
}
else if(value == 1)
{
value = 0;
}
return value;
}
}
Is access through 'Instance' to the 'Toggle()' class threadsafe? If yes, by what assumptions, rules, etc. If no, why and how can I fix it?
No, it's not threadsafe.
Basically, both threads can run the Toggle function at the same time, so this could happen
// thread 1 is running this code
if(value == 0)
{
value = 1;
// RIGHT NOW, thread 2 steps in.
// It sees value as 1, so runs the other branch, and changes it to 0
// This causes your method to return 0 even though you actually want 1
}
else if(value == 1)
{
value = 0;
}
return value;
You need to operate with the following assumption.
If 2 threads are running, they can and will interleave and interact with eachother randomly at any point. You can be half way through writing or reading a 64 bit integer or float (on a 32 bit CPU) and another thread can jump in and change it out from underneath you.
If the 2 threads never access anything in common, it doesn't matter, but as soon as they do, you need to prevent them from stepping on each others toes. The way to do this in .NET is with locks.
You can decide what and where to lock by thinking about things like this:
For a given block of code, if the value of something got changed out from underneath me, would it matter? If it would, you need to lock that something for the duration of the code where it would matter.
Looking at your example again
// we read value here
if(value == 0)
{
value = 1;
}
else if(value == 1)
{
value = 0;
}
// and we return it here
return value;
In order for this to return what we expect it to, we assume that value won't get changed between the read and the return. In order for this assumption to actually be correct, you need to lock value for the duration of that code block.
So you'd do this:
lock( value )
{
if(value == 0)
... // all your code here
return value;
}
HOWEVER
In .NET you can only lock Reference Types. Int32 is a Value Type, so we can't lock it.
We solve this by introducing a 'dummy' object, and locking that wherever we'd want to lock 'value'.
This is what Ben Scheirman is referring to.
The original impplementation is not thread safe, as Ben points out
A simple way to make it thread safe is to introduce a lock statement. Eg. like this:
public class MyClass
{
private Object thisLock = new Object();
private static readonly MyClass instance = new MyClass();
public static MyClass Instance
{
get { return instance; }
}
private Int32 value = 0;
public Int32 Toggle()
{
lock(thisLock)
{
if(value == 0)
{
value = 1;
}
else if(value == 1)
{
value = 0;
}
return value;
}
}
}
I'd also add a protected constructor to MyClass to prevent the compiler from generating a public default constructor.
That is what I thought. But, I I'm
looking for the details... 'Toggle()'
is not a static method, but it is a
member of a static property (when
using 'Instance'). Is that what makes
it shared among threads?
If your application is multi-threaded and you can forsee that multiple thread will access that method, that makes it shared among threads. Because your class is a Singleton you know that the diferent thread will access the SAME object, so be cautioned about the thread-safety of your methods.
And how does this apply to singletons
in general. Would I have to address
this in every method on my class?
As I said above, because its a singleton you know diferent thread will acess the same object, possibly at the same time. This does not mean you have to make every method obtain a lock. If you notice that a simultaneos invocation can lead to corrupted state of the class, then you should apply the method mentioned by #Thomas
Can I assume that the singleton pattern exposes my otherwise lovely thread-safe class to all the thread problems of regular static members?
No. Your class is simply not threadsafe. The singleton has nothing to do with it.
(I'm getting my head around the fact that instance members called on a static object cause threading problems)
It's nothing to do with that either.
You have to think like this: Is it possible in my program for 2 (or more) threads to access this piece of data at the same time?
The fact that you obtain the data via a singleton, or static variable, or passing in an object as a method parameter doesn't matter. At the end of the day it's all just some bits and bytes in your PC's RAM, and all that matters is whether multiple threads can see the same bits.
Your thread could stop in the middle of that method and transfer control to a different thread. You need a critical section around that code...
private static object _lockDummy = new object();
...
lock(_lockDummy)
{
//do stuff
}
I was thinking that if I dump the singleton pattern and force everyone to get a new instance of the class it would ease some problems... but that doesn't stop anyone else from initializing a static object of that type and passing that around... or from spinning off multiple threads, all accessing 'Toggle()' from the same instance.
Bingo :-)
I get it now. It's a tough world. I wish I weren't refactoring legacy code :(
Unfortunately, multithreading is hard and you have to be very paranoid about things :-)
The simplest solution in this case is to stick with the singleton, and add a lock around the value, like in the examples.
Quote:
if(value == 0) { value = 1; }
if(value == 1) { value = 0; }
return value;
value will always be 0...
Well, I actually don't know C# that well... but I am ok at Java, so I will give the answer for that, and hopefully the two are similar enough that it will be useful. If not, I apologize.
The answer is, no, it's not safe. One thread could call Toggle() at the same time as the other, and it is possible, although unlikely with this code, that Thread1 could set value in between the times that Thread2 checks it and when it sets it.
To fix, simply make Toggle() synchronized. It doesn't block on anything or call anything that might spawn another thread which could call Toggle(), so that's all you have to do save it.

Categories