diff --git a/mono/Assistance/Document.cs b/mono/Assistance/Document.cs
index ef232d0..8af4cbc 100644
--- a/mono/Assistance/Document.cs
+++ b/mono/Assistance/Document.cs
@@ -10,9 +10,8 @@ namespace Assistance {
 		public readonly List<ActivePoint> points = new List<ActivePoint>();
 		public readonly Canvas canvas = new Canvas();
 		
-		public Document(Workarea workarea) {
-			this.workarea = workarea;
-		}
+		public Document(Workarea workarea)
+			{ this.workarea = workarea; }
 	}
 }
 
diff --git a/mono/Assistance/Guideline.cs b/mono/Assistance/Guideline.cs
index 923ac19..19d822b 100644
--- a/mono/Assistance/Guideline.cs
+++ b/mono/Assistance/Guideline.cs
@@ -9,9 +9,7 @@ namespace Assistance {
 		public static readonly double snapLenght = 20.0;
 		public static readonly double snapScale = 1.0;
 	
-		public virtual Point transformPoint(Point p) {
-			return p;
-		}
+		public virtual Track.WayPoint transformPoint(Track.WayPoint point) { }
 		
 		public virtual void draw(Cairo.Context context, bool active) { }
 
diff --git a/mono/Assistance/InputManager.cs b/mono/Assistance/InputManager.cs
index 99b0acf..b66d7b5 100644
--- a/mono/Assistance/InputManager.cs
+++ b/mono/Assistance/InputManager.cs
@@ -15,17 +15,36 @@ namespace Assistance {
 		public class KeyPoint {
 			public class Holder: IDisposable {
 				public readonly KeyPoint keyPoint;
-				private bool disposed = false;
+				private bool holded = false;
+				
 				public Holder(KeyPoint keyPoint)
-					{ this.keyPoint = keyPoint; ++keyPoint.refCount; }
+					{ this.keyPoint = keyPoint; reuse(); }
+
+				public bool available
+					{ get { return keyPoint.available; } }
+				public bool isHolded
+					{ get { return holded; } }
+				public bool reuse() {
+					if (!holded) ++keyPoint.refCount;
+					holded = true;
+					return keyPoint.available;
+				}
+				public void release() {
+					if (holded) --keyPoint.refCount;
+					holded = false;
+				}
+					
 				public void Dispose()
 					{ Dispose(true); GC.SuppressFinalize(this); }
 				protected virtual void Dispose(bool disposing)
-					{ if (!disposed) --keyPoint.refCount; disposed = true; }
+					{  release(); }
 				~Holder()
 					{ Dispose(false); }
 			}
+			
 			private int refCount = 0;
+			public bool available = true;
+			
 			public Holder hold()
 				{ return new Holder(this); }
 			public bool isFree
@@ -80,6 +99,7 @@ namespace Assistance {
 				track.wayPointsRemoved = 0;
 				track.wayPointsAdded = track.points.Count - index - 1;
 			}
+			for(int i = level; i < keyPoints.Count; ++i) keyPoints[i].available = false;
 			keyPoints.RemoveRange(level, keyPoints.Count - level);
 		}
 		
@@ -87,7 +107,7 @@ namespace Assistance {
 			if (count <= 0)
 				return;
 			
-			level = keyPoints.Count - count;
+			int level = keyPoints.Count - count;
 			if (level >= keyPointsSent || tool.paintApply(keyPointsSent - level)) {
 				// apply
 				foreach(Track track in subTracks)
@@ -104,6 +124,7 @@ namespace Assistance {
 				}
 			}
 
+			for(int i = level; i < keyPoints.Count; ++i) keyPoints[i].available = false;
 			keyPoints.RemoveRange(level, keyPoints.Count - level);
 			if (level < keyPointsSent)
 				keyPointsSent = level;
diff --git a/mono/Assistance/InputModifierAssistants.cs b/mono/Assistance/InputModifierAssistants.cs
new file mode 100644
index 0000000..f745001
--- /dev/null
+++ b/mono/Assistance/InputModifierAssistants.cs
@@ -0,0 +1,98 @@
+using System;
+using System.Diagnostics;
+using System.Collections.Generic;
+
+namespace Assistance {
+	public class InputModifierAssistants: InputModifierTangents {
+		public readonly Workarea workarea;
+		public readonly bool interpolate;
+		
+		public InputModifierAssistants(Workarea workarea, bool interpolate = false, double precision = 1.0):
+			base(precision)
+		{
+			this.workarea = workarea;
+			this.interpolate = interpolate;
+		}
+		
+		public class Modifier: Track.Modifier {
+			public Modifier(Track.Handler handler):
+				base(handler) { }
+			
+			public InputManager.KeyPoint.Holder holder = null;
+			public List<Guideline> guidelines = new List<Guideline>();
+			
+			public override Track.WayPoint calcWayPoint(double originalIndex) {
+				Track.WayPoint p = original.calcWayPoint(originalIndex);
+				return guidelines.Count > 0 ? guidelines[0].transformPoint(p) : p;
+			}
+		}
+
+		public override List<Track> modify(Track track, InputManager.KeyPoint keyPoint, List<Track> outTracks) {
+			Track subTrack;
+			Modifier modifier;
+			
+			if (track.handler == null) {
+				if (track.points.Count == 0)
+					return;
+
+				Track.Handler handler = new Track.Handler(this, track);
+				modifier = new Track.Modifier(track.handler);
+				workarea.getGuidelines(modifier.guidelines, track.points[0].point.position);
+				if (interpolate && modifier.guidelines.Count == 0)
+					{ base.modify(track, keyPoint, outTracks); return; }
+				
+				track.handler = handler;
+				subTrack = new Track(modifier);
+				track.handler.tracks.Add(subTrack);
+				
+				if (modifier.guidelines.Count > 1) {
+					modifier.holder = keyPoint.hold();
+					outTracks.Add(subTrack);
+					return;
+				}
+			}
+			
+			subTrack = track.handler.tracks[0];
+			if (subTrack.modifier is InputModifierTangents.Modifier)
+				{ base.modify(track, keyPoint, outTracks); return; }
+			
+			modifier = (Modifier)subTrack.modifier;
+			outTracks.Add(subTrack);
+			
+			if (!track.isChanged)
+				return;
+			
+			// remove points
+			int start = track.points.Count - track.wayPointsAdded;
+			if (start < 0) start = 0;
+			if (subTrack.points.Count < start) {
+				subTrack.points.RemoveRange(start, subTrack.points.Count - start);
+				subTrack.wayPointsRemoved += subTrack.points.Count - start;
+			}
+			
+			bool trackIsLong = track.points.Count > 0 && track.getLast().length > 2.0*Guideline.snapLenght;
+			if (!trackIsLong && modifier.holder != null && !modifier.holder.isHolded && modifier.holder.available)
+				modifier.holder.reuse();
+			
+			// select guideline
+			if (modifier.holder != null && modifier.holder.isHolded) {
+				Guideline guideline = Guideline.findBest(modifier.guidelines, track);
+				if (guideline != modifier.guidelines[0]) {
+					modifier.guidelines[ modifier.guidelines.IndexOf(guideline) ] = modifier.guidelines[0];
+					modifier.guidelines[0] = guideline;
+					start = 0;
+					subTrack.wayPointsRemoved += subTrack.points.Count;
+					subTrack.points.Clear;
+				}
+				if (trackIsLong)
+					modifier.holder.release();
+			}
+			
+			// add points
+			for(int i = start; i < track.points.Count; ++i)
+				subTrack.points.Add(modifier.calcWayPoint(i));
+			subTrack.wayPointsAdded = subTrack.points.Count - start;
+		}
+	}
+}
+
diff --git a/mono/Assistance/InputModifierInterpolation.cs b/mono/Assistance/InputModifierInterpolation.cs
index f526038..f9b9545 100644
--- a/mono/Assistance/InputModifierInterpolation.cs
+++ b/mono/Assistance/InputModifierInterpolation.cs
@@ -6,9 +6,9 @@ namespace Assistance {
 		public readonly double precision;
 		public readonly double precisionSqr;
 		
-		public InputModifierInterpolation(double precision = 0.0) {
-			this.precision = precision;
-			this.precisionSqr = precision*precision;
+		public InputModifierInterpolation(double precision = 1.0) {
+			this.precision = Math.Max(precision, Geometry.precision);
+			this.precisionSqr = this.precision*this.precision;
 		}
 	
 		public void addSegment(Track track, Track.WayPoint p0, Track.WayPoint p1) {
@@ -37,7 +37,7 @@ namespace Assistance {
 			if (start < 0) start = 0;
 			int subStart = subTrack.floorIndex(subTrack.indexByOriginalIndex(start));
 			if (subTrack.points.Count < subStart) {
-				subTrack.points.RemoveRange(start, subTrack.points.Count - subStart);
+				subTrack.points.RemoveRange(subStart, subTrack.points.Count - subStart);
 				subTrack.wayPointsRemoved += subTrack.points.Count - subStart;
 			}
 			
diff --git a/mono/Assistance/InputModifierTangents.cs b/mono/Assistance/InputModifierTangents.cs
index dba5aaf..66c177e 100644
--- a/mono/Assistance/InputModifierTangents.cs
+++ b/mono/Assistance/InputModifierTangents.cs
@@ -85,7 +85,10 @@ namespace Assistance {
 				subTrack.wayPointsAdded += index - start;
 				
 				// release previous key point
-				if (modifier.holder) modifier.holder.Dispose();
+				if (modifier.holder) {
+					modifier.holder.Dispose();
+					modifier.holder = null;
+				}
 				
 				if (track.isFinished) {
 					// finish
diff --git a/mono/Assistance/Modifier.cs b/mono/Assistance/Modifier.cs
index 5337b5c..72630d0 100644
--- a/mono/Assistance/Modifier.cs
+++ b/mono/Assistance/Modifier.cs
@@ -3,7 +3,7 @@ using System.Collections.Generic;
 using Assistance.Drawing;
 
 namespace Assistance {
-	public class Modifier: ActivePoint.Owner {
+	public class Modifier: ActivePoint.Owner, InputModifier {
 		public static readonly Pen pen = new Pen("Light Gray");
 
 		public Modifier(Document document): base(document) {
@@ -20,18 +20,10 @@ namespace Assistance {
 			document.modifiers.Add(this);
 		}
 
-		public virtual void draw(Cairo.Context context) { }
+		public virtual void activate() { }
+		public virtual List<Track> modify(List<Track> tracks) { return tracks; }
+		public virtual void deactivate() { }
 
-		public virtual void getTransformFuncs(List<Geometry.TransformFunc> transformFuncs) { }
-		
-		public List<Track> modify(List<Track> tracks) {
-			List<Track> outTracks = new List<Track>();
-			List<Geometry.TransformFunc> transformFuncs = new List<Geometry.TransformFunc>();
-			getTransformFuncs(transformFuncs);
-			foreach(Track track in tracks)
-				foreach(Geometry.TransformFunc transformFunc in transformFuncs)
-					outTracks.Add(track.createChild(transformFunc));
-			return outTracks;
-		}
+		public virtual void draw(Cairo.Context context) { }
 	}
 }