diff --git a/mono/Assistance/ActivePoint.cs b/mono/Assistance/ActivePoint.cs
index 78e43b6..d546505 100644
--- a/mono/Assistance/ActivePoint.cs
+++ b/mono/Assistance/ActivePoint.cs
@@ -10,11 +10,23 @@ namespace Assistance {
 			CircleCross,
 		};
 
-		public class Owner {
-			public readonly Document document;
-			public readonly List<ActivePoint> points = new List<ActivePoint>();
+		public interface IOwner {
+			Document document { get; }
+			List<ActivePoint> points { get; }
 			
-			public Owner(Document document) { this.document = document; }
+			void onMovePoint(ActivePoint point, Point position);
+			void bringToFront();
+			void remove();
+		}
+
+		public class Owner: IOwner {
+			private readonly Document privateDocument;
+			private readonly List<ActivePoint> privatePoints = new List<ActivePoint>();
+
+			public Document document { get { return privateDocument; } }
+			public List<ActivePoint> points { get { return privatePoints; } }
+
+			public Owner(Document document) { this.privateDocument = document; }
 			public virtual void onMovePoint(ActivePoint point, Point position) { point.position = position; }
 			public virtual void bringToFront() { }
 			public virtual void remove() { foreach(ActivePoint point in points) document.points.Remove(point); }
@@ -28,11 +40,11 @@ namespace Assistance {
 		public static readonly Brush brushActive = new Brush("Light Blue");
 
 		public readonly Document document;
-		public readonly Owner owner;
+		public readonly IOwner owner;
 		public readonly Type type;
 		public Point position;
 
-		public ActivePoint(Owner owner, Type type, Point position = new Point()) {
+		public ActivePoint(IOwner owner, Type type, Point position = new Point()) {
 			this.document = owner.document;
 			this.owner = owner;
 			this.type = type;
diff --git a/mono/Assistance/Assistance.csproj b/mono/Assistance/Assistance.csproj
index f8b5b22..fd7d1c5 100644
--- a/mono/Assistance/Assistance.csproj
+++ b/mono/Assistance/Assistance.csproj
@@ -34,9 +34,7 @@
   <Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
   <ItemGroup>
     <Compile Include="MainWindow.cs" />
-    <Compile Include="Assistant.cs">
-      <DependentUpon>AssistantGrid.cs</DependentUpon>
-    </Compile>
+    <Compile Include="Assistant.cs" />
     <Compile Include="ActivePoint.cs" />
     <Compile Include="Point.cs" />
     <Compile Include="Workarea.cs" />
@@ -46,18 +44,13 @@
     <Compile Include="Guideline.cs" />
     <Compile Include="GuidelineLine.cs" />
     <Compile Include="AssistantVanishingPoint.cs" />
-    <Compile Include="AssistantGrid.cs" />
     <Compile Include="Geometry.cs" />
-    <Compile Include="Modifier.cs">
-      <DependentUpon>Point.cs</DependentUpon>
-    </Compile>
+    <Compile Include="Modifier.cs" />
     <Compile Include="ModifierSnowflake.cs" />
     <Compile Include="Document.cs" />
     <Compile Include="Tool.cs" />
     <Compile Include="Drawing.cs" />
-    <Compile Include="KeyState.cs">
-      <DependentUpon>MainWindow.cs</DependentUpon>
-    </Compile>
+    <Compile Include="KeyState.cs" />
     <Compile Include="Timer.cs" />
     <Compile Include="InputState.cs" />
     <Compile Include="InputModifierAssistants.cs" />
diff --git a/mono/Assistance/Assistant.cs b/mono/Assistance/Assistant.cs
index 19d7123..8bc0806 100644
--- a/mono/Assistance/Assistant.cs
+++ b/mono/Assistance/Assistant.cs
@@ -3,13 +3,10 @@ using System.Collections.Generic;
 
 namespace Assistance {
 	public class Assistant: ActivePoint.Owner {
-		public static readonly double maxLen = 1000.0;
-		//public static readonly int gridPointsCount = 100;
 		public static readonly Drawing.Pen pen = new Drawing.Pen("gray");
 
-		public Assistant(Document document): base(document) {
-			document.assistants.Add(this);
-		}
+		public Assistant(Document document): base(document)
+			{ document.assistants.Add(this); }
 
 		public override void remove() {
 			base.remove();
@@ -21,14 +18,6 @@ namespace Assistance {
 			document.assistants.Add(this);
 		}
 
-		// TODO: ?
-		//public double getMaxLen() {
-		//	double l = 0.0;
-		//	foreach(ActivePoint point in points)
-		//		l = Math.Max(l, point.position.len());
-		//	return maxLen + l;
-		//}
-
 		public virtual void draw(Cairo.Context context) { }
 
 		public virtual void getGuidelines(List<Guideline> outGuidelines, Point target) { }
diff --git a/mono/Assistance/AssistantGrid.cs b/mono/Assistance/AssistantGrid.cs
deleted file mode 100644
index db26c0f..0000000
--- a/mono/Assistance/AssistantGrid.cs
+++ /dev/null
@@ -1,22 +0,0 @@
-using System;
-
-namespace Assistance {
-	public class AssistantGrid: Assistant {
-		public ActivePoint center;
-
-		public AssistantGrid(Document document, Point center): base(document) {
-			this.center = new ActivePoint(this, ActivePoint.Type.CircleCross, center);
-		}
-
-		public override void draw(Cairo.Context context) {
-			/*
-			foreach(Assistant assistant in canvas.assistants)
-				foreach(Point p in assistant.getGridPoints(center.position))
-					foreach(Assistant a in canvas.assistants)
-						if (a != assistant)
-							a.drawGuidlines(context, p);
-			*/
-		}
-	}
-}
-
diff --git a/mono/Assistance/Geometry.cs b/mono/Assistance/Geometry.cs
index e9174cc..e2da322 100644
--- a/mono/Assistance/Geometry.cs
+++ b/mono/Assistance/Geometry.cs
@@ -66,19 +66,19 @@ namespace Assistance {
    				{ // mul
    					ParameterExpression a = Expression.Parameter(typeof(T));
 				    ParameterExpression b = Expression.Parameter(typeof(double));
-				    mul = Expression.Lambda<FullFunc>(Expression.Multiply(a, b), a, b).Compile();
+				    mul = Expression.Lambda<HalfFunc>(Expression.Multiply(a, b), a, b).Compile();
 				}
    				{ // div
    					ParameterExpression a = Expression.Parameter(typeof(T));
 				    ParameterExpression b = Expression.Parameter(typeof(double));
-				    div = Expression.Lambda<FullFunc>(Expression.Divide(a, b), a, b).Compile();
+				    div = Expression.Lambda<HalfFunc>(Expression.Divide(a, b), a, b).Compile();
 				}
    			}
    			
 			public static T linear(T p0, T p1, double l)
 				{ return add(mul(sub(p1, p0), l), p0); }
 	
-			public static double spline(T p0, T p1, T t0, T t1, double l) {
+			public static T spline(T p0, T p1, T t0, T t1, double l) {
 				double ll = l*l;
 				double lll = ll*l;
 				return add( add( mul(p0, ( 2.0*lll - 3.0*ll + 1.0)),
@@ -87,7 +87,7 @@ namespace Assistance {
 				                 mul(t1, (     lll - 1.0*ll      )) ));
 	        }
 	
-			public static double splineTangent(T p0, T p1, T t0, T t1, double l) {
+			public static T splineTangent(T p0, T p1, T t0, T t1, double l) {
 				double ll = l*l;
 				return add( mul(sub(p0, p1), 6.0*(ll - l)),
 				            add( mul(t0, ( 3.0*ll - 4.0*l + 1.0)),
diff --git a/mono/Assistance/Guideline.cs b/mono/Assistance/Guideline.cs
index 19d822b..d224c70 100644
--- a/mono/Assistance/Guideline.cs
+++ b/mono/Assistance/Guideline.cs
@@ -8,14 +8,15 @@ namespace Assistance {
 		public static readonly Pen penActive = new Pen("Deep Sky Blue");
 		public static readonly double snapLenght = 20.0;
 		public static readonly double snapScale = 1.0;
+		public static readonly double maxLenght = 2.0*snapLenght*snapScale;
 	
-		public virtual Track.WayPoint transformPoint(Track.WayPoint point) { }
+		public virtual Track.WayPoint transformPoint(Track.WayPoint point)
+			{ return point; }
 		
 		public virtual void draw(Cairo.Context context, bool active) { }
 
-		public void draw(Cairo.Context context) {
-			draw(context, false);
-		}
+		public void draw(Cairo.Context context)
+			{ draw(context, false); }
 		
 		public double calcTrackWeight(Track track) {
 			if (track.points.Count < 1)
@@ -24,9 +25,9 @@ namespace Assistance {
 			double sumLength = 0.0;
 			double sumDeviation = 0.0;
 			
-			Point prev = track.points[0].point;
-			foreach(TrackPoint tp in track.points) {
-				Point p = tp.point;
+			Point prev = track.points[0].point.position;
+			foreach(Track.WayPoint wp in track.points) {
+				Point p = wp.point.position;
 				double length = (p - prev).len();
 				sumLength += length;
 				
@@ -35,7 +36,8 @@ namespace Assistance {
 					double weight = length*Geometry.logNormalDistribuitionUnscaled(midStepLength, snapLenght, snapScale);
 					sumWeight += weight;
 				
-					double deviation = (transformPoint(p) - p).len();
+					Track.WayPoint nwp = transformPoint(wp);
+					double deviation = (nwp.point.position - p).len();
 					sumDeviation += weight*deviation;
 				}
 				prev = p;
diff --git a/mono/Assistance/GuidelineLine.cs b/mono/Assistance/GuidelineLine.cs
index cb67efd..77c993d 100644
--- a/mono/Assistance/GuidelineLine.cs
+++ b/mono/Assistance/GuidelineLine.cs
@@ -26,8 +26,11 @@ namespace Assistance {
 			context.Restore();
 		}
 		
-		public override Point transformPoint(Point p) {
-			return Point.dot(p - p0, direction)*direction + p0;
+		public override Track.WayPoint transformPoint(Track.WayPoint p) {
+			Track.WayPoint np = p;
+			np.point.position = Point.dot(p.point.position - p0, direction)*direction + p0;
+			np.tangent.position = direction;
+			return np;
 		}
 	}
 }
diff --git a/mono/Assistance/InputManager.cs b/mono/Assistance/InputManager.cs
index b66d7b5..ddd1903 100644
--- a/mono/Assistance/InputManager.cs
+++ b/mono/Assistance/InputManager.cs
@@ -2,13 +2,13 @@ using System;
 using System.Collections.Generic;
 
 namespace Assistance {
-	public class InputManager: Track.Owner {
+	public class InputManager: Track.IOwner {
 		public static readonly Drawing.Pen penPreview = new Drawing.Pen("Dark Green", 1.0, 0.25);
 
 		public class TrackHandler: Track.Handler {
 			public readonly List<int> keys = new List<int>();
 			public TrackHandler(InputManager owner, Track original, int keysCount = 0):
-				base(owner, track)
+				base(owner, original)
 				{ for(int i = 0; i < keysCount; ++i) keys.Add(0); }
 		}
 		
@@ -51,10 +51,15 @@ namespace Assistance {
 				{ get { return refCount <= 0; } }
 		}
 		
-		public class Modifier: Track.Owner {
+		public interface IModifier: Track.IOwner {
+			void activate();
+			void modify(List<Track> tracks, KeyPoint keyPoint, List<Track> outTracks);
+			void deactivate();
+		}
+
+		public class Modifier: IModifier {
 			public virtual void activate() { }
-			public virtual void modify(Track tracks, KeyPoint keyPoint, List<Track> outTracks)
-				{ }
+			public virtual void modify(Track track, KeyPoint keyPoint, List<Track> outTracks) { }
 			public virtual void modify(List<Track> tracks, KeyPoint keyPoint, List<Track> outTracks)
 				{ foreach(Track track in tracks) modify(track, keyPoint, outTracks); }
 			public virtual void deactivate() { }
@@ -66,7 +71,7 @@ namespace Assistance {
 		private readonly InputState state = new InputState();
 
 		private Tool tool;
-		private readonly List<Modifier> modifiers = new List<Modifier>();
+		private readonly List<IModifier> modifiers = new List<IModifier>();
 
 		private readonly List<Track> tracks = new List<Track>();
 		private readonly List<KeyPoint> keyPoints = new List<KeyPoint>();
@@ -86,7 +91,7 @@ namespace Assistance {
 			
 			int level = keyIndex + 1;
 			if (level <= keyPointsSent) {
-				if (level <= keyPointsSent)
+				if (level < keyPointsSent)
 					tool.paintPop(keyPointsSent - level);
 				tool.paintCancel();
 				keyPointsSent = level;
@@ -95,45 +100,51 @@ namespace Assistance {
 			foreach(Track track in subTracks) {
 				TrackHandler handler = (TrackHandler)track.handler;
 				handler.keys.RemoveRange(level, keyPoints.Count - level);
-				int index = handler.keys[keyIndex];
+				int cnt = handler.keys[keyIndex];
 				track.wayPointsRemoved = 0;
-				track.wayPointsAdded = track.points.Count - index - 1;
+				track.wayPointsAdded = track.points.Count - cnt;
 			}
 			for(int i = level; i < keyPoints.Count; ++i) keyPoints[i].available = false;
 			keyPoints.RemoveRange(level, keyPoints.Count - level);
 		}
 		
-		private void paintApply(int count, Dictionary<long, Track> subTracks) {
+		private void paintApply(int count, List<Track> subTracks) {
 			if (count <= 0)
 				return;
 			
 			int level = keyPoints.Count - count;
-			if (level >= keyPointsSent || tool.paintApply(keyPointsSent - level)) {
+			
+			if (level < keyPointsSent) {
 				// apply
-				foreach(Track track in subTracks)
-					((TrackHandler)track.handler).keys.RemoveRange(level, keyPoints.Count - level);
-			} else {
+				keyPointsSent -= tool.paintApply(keyPointsSent - level);
+				foreach(Track track in subTracks) {
+					TrackHandler handler = (TrackHandler)track.handler;
+					handler.keys.RemoveRange(keyPointsSent, handler.keys.Count - keyPointsSent);
+				}
+			}
+
+			if (level < keyPointsSent) {
 				// rollback
 				tool.paintPop(keyPointsSent - level);
+				keyPointsSent = level;
 				foreach(Track track in subTracks) {
 					TrackHandler handler = (TrackHandler)track.handler;
-					int index = handler.keys[level];
-					handler.keys.RemoveRange(level, keyPoints.Count - level);
+					int cnt = handler.keys[keyPointsSent];
+					handler.keys.RemoveRange(keyPointsSent, handler.keys.Count - keyPointsSent);
 					track.wayPointsRemoved = 0;
-					track.wayPointsAdded = track.points.Count - index - 1;
+					track.wayPointsAdded = track.points.Count - cnt;
 				}
 			}
 
+			// remove keypoints
 			for(int i = level; i < keyPoints.Count; ++i) keyPoints[i].available = false;
 			keyPoints.RemoveRange(level, keyPoints.Count - level);
-			if (level < keyPointsSent)
-				keyPointsSent = level;
 		}
 		
 		private void paintTracks() {
 			bool allFinished = true;
 			foreach(Track track in tracks)
-				if (!track.isFinished)
+				if (!track.isFinished())
 					{ allFinished = false; break; }
 
 			while(true) {
@@ -141,9 +152,9 @@ namespace Assistance {
 				KeyPoint newKeyPoint = new KeyPoint();
 				subTracks = tracks;
 				int i = 0;
-				foreach(Modifier modifier in modifiers) {
+				foreach(IModifier modifier in modifiers) {
 					List<Track> outTracks = subTracksBuf[i];
-					modifier.modify(subTracks, keyEvent, outTracks);
+					modifier.modify(subTracks, newKeyPoint, outTracks);
 					subTracks = outTracks;
 					i = 1 - i;
 				}
@@ -182,9 +193,7 @@ namespace Assistance {
 					if (allFinished) {
 						paintApply(keyPoints.Count, subTracks);
 						tracks.Clear();
-						this.subTracks = null;
-					} else {
-						this.subTracks = subTracks;
+						this.subTracks.Clear();
 					}
 					break;
 				}
@@ -198,8 +207,8 @@ namespace Assistance {
 		}
 		
 		private int trackCompare(Track track, Gdk.Device device, long touchId) {
-			if (track.device < device) return -1;
-			if (track.device > device) return 1;
+			if (track.device.Handle.ToInt64() < device.Handle.ToInt64()) return -1;
+			if (track.device.Handle.ToInt64() > device.Handle.ToInt64()) return 1;
 			if (track.touchId < touchId) return -1;
 			if (track.touchId > touchId) return 1;
 			return 0;
@@ -275,8 +284,8 @@ namespace Assistance {
 		
 		public void trackEvent(long touchId, Gdk.Device device, Track.Point point, bool final, long ticks) {
 			if (tool != null) {
-				Track track = getTrack(touchId, device, ticks);
-				if (!track.isFinished) {
+				Track track = getTrack(device, touchId, ticks);
+				if (!track.isFinished()) {
 					double time = (double)(ticks - track.keyHistory.ticks)*Timer.step - track.keyHistory.timeOffset;
 					addTrackPoint(track, point, time, final);
 					paintTracks();
@@ -320,23 +329,23 @@ namespace Assistance {
 		
 		public int getModifiersCount()
 			{ return modifiers.Count; }
-		public Modifier getModifier(int index)
+		public IModifier getModifier(int index)
 			{ return modifiers[index]; }
 
-		public void insertModifier(int index, Modifier modifier) {
+		public void insertModifier(int index, IModifier modifier) {
 			if (this.tool != null) finishTracks();
 			modifiers.Insert(index, modifier);
 			modifier.activate();
 		}
-		public void addModifier(Modifier modifier)
+		public void addModifier(IModifier modifier)
 			{ insertModifier(getModifiersCount(), modifier); }
 		
 		public void removeModifier(int index) {
 			if (this.tool != null) finishTracks();
-			modifiers[i].deactivate();
+			modifiers[index].deactivate();
 			modifiers.RemoveAt(index);
 		}
-		public void removeModifier(Modifier modifier) {
+		public void removeModifier(IModifier modifier) {
 			for(int i = 0; i < getModifiersCount(); ++i)
 				if (getModifier(i) == modifier)
 					{ removeModifier(i); break; }
diff --git a/mono/Assistance/InputModifierAssistants.cs b/mono/Assistance/InputModifierAssistants.cs
index f745001..5a9adf1 100644
--- a/mono/Assistance/InputModifierAssistants.cs
+++ b/mono/Assistance/InputModifierAssistants.cs
@@ -7,14 +7,12 @@ namespace Assistance {
 		public readonly Workarea workarea;
 		public readonly bool interpolate;
 		
-		public InputModifierAssistants(Workarea workarea, bool interpolate = false, double precision = 1.0):
-			base(precision)
-		{
+		public InputModifierAssistants(Workarea workarea, bool interpolate = false) {
 			this.workarea = workarea;
 			this.interpolate = interpolate;
 		}
 		
-		public class Modifier: Track.Modifier {
+		public new class Modifier: Track.Modifier {
 			public Modifier(Track.Handler handler):
 				base(handler) { }
 			
@@ -27,7 +25,7 @@ namespace Assistance {
 			}
 		}
 
-		public override List<Track> modify(Track track, InputManager.KeyPoint keyPoint, List<Track> outTracks) {
+		public override void modify(Track track, InputManager.KeyPoint keyPoint, List<Track> outTracks) {
 			Track subTrack;
 			Modifier modifier;
 			
@@ -36,7 +34,7 @@ namespace Assistance {
 					return;
 
 				Track.Handler handler = new Track.Handler(this, track);
-				modifier = new Track.Modifier(track.handler);
+				modifier = new Modifier(track.handler);
 				workarea.getGuidelines(modifier.guidelines, track.points[0].point.position);
 				if (interpolate && modifier.guidelines.Count == 0)
 					{ base.modify(track, keyPoint, outTracks); return; }
@@ -70,7 +68,7 @@ namespace Assistance {
 				subTrack.wayPointsRemoved += subTrack.points.Count - start;
 			}
 			
-			bool trackIsLong = track.points.Count > 0 && track.getLast().length > 2.0*Guideline.snapLenght;
+			bool trackIsLong = track.points.Count > 0 && track.getLast().length >= Guideline.maxLenght;
 			if (!trackIsLong && modifier.holder != null && !modifier.holder.isHolded && modifier.holder.available)
 				modifier.holder.reuse();
 			
@@ -82,7 +80,7 @@ namespace Assistance {
 					modifier.guidelines[0] = guideline;
 					start = 0;
 					subTrack.wayPointsRemoved += subTrack.points.Count;
-					subTrack.points.Clear;
+					subTrack.points.Clear();
 				}
 				if (trackIsLong)
 					modifier.holder.release();
diff --git a/mono/Assistance/InputModifierInterpolation.cs b/mono/Assistance/InputModifierInterpolation.cs
index f9b9545..51c63d7 100644
--- a/mono/Assistance/InputModifierInterpolation.cs
+++ b/mono/Assistance/InputModifierInterpolation.cs
@@ -19,14 +19,14 @@ namespace Assistance {
 			addSegment(track, p, p1);
 		}
 	
-		public override List<Track> modify(Track track, InputManager.KeyPoint keyPoint, List<Track> outTracks) {
+		public override void modify(Track track, InputManager.KeyPoint keyPoint, List<Track> outTracks) {
 			if (track.handler == null) {
 				track.handler = new Track.Handler(this, track);
 				track.handler.tracks.Add(new Track( new Track.Modifier(track.handler) ));
 			}
 			
 			Track subTrack = track.handler.tracks[0];
-			Modifier modifier = (Modifier)subTrack.modifier;
+			Track.Modifier modifier = subTrack.modifier;
 			outTracks.Add(subTrack);
 			
 			if (!track.isChanged)
diff --git a/mono/Assistance/InputModifierTangents.cs b/mono/Assistance/InputModifierTangents.cs
index 66c177e..360448f 100644
--- a/mono/Assistance/InputModifierTangents.cs
+++ b/mono/Assistance/InputModifierTangents.cs
@@ -4,7 +4,7 @@ using System.Collections.Generic;
 namespace Assistance {
 	public class InputModifierTangents: InputManager.Modifier {
 		public class Modifier: Track.Modifier {
-			public Modifier(Handler handler):
+			public Modifier(Track.Handler handler):
 				base(handler) { }
 			
 			public InputManager.KeyPoint.Holder holder = null;
@@ -22,7 +22,7 @@ namespace Assistance {
 			}
 		}
 
-		public override List<Track> modify(Track track, InputManager.KeyPoint keyPoint, List<Track> outTracks) {
+		public override void modify(Track track, InputManager.KeyPoint keyPoint, List<Track> outTracks) {
 			if (track.handler == null) {
 				track.handler = new Track.Handler(this, track);
 				track.handler.tracks.Add(new Track( new Modifier(track.handler) ));
@@ -85,12 +85,12 @@ namespace Assistance {
 				subTrack.wayPointsAdded += index - start;
 				
 				// release previous key point
-				if (modifier.holder) {
+				if (modifier.holder != null) {
 					modifier.holder.Dispose();
 					modifier.holder = null;
 				}
 				
-				if (track.isFinished) {
+				if (track.isFinished()) {
 					// finish
 					modifier.tangents.Add(new Track.Point());
 					subTrack.points.Add(track.getLast());
diff --git a/mono/Assistance/InputState.cs b/mono/Assistance/InputState.cs
index 2ba3adc..d204437 100644
--- a/mono/Assistance/InputState.cs
+++ b/mono/Assistance/InputState.cs
@@ -43,7 +43,7 @@ namespace Assistance {
 			return history;
 		}
 		public KeyState<uint> buttonState(Gdk.Device device)
-			{ buttonHistory(device).current; }
+			{ return buttonHistory(device).current; }
 
 		public void buttonEvent(bool press, Gdk.Device device, uint button, long ticks) {
 			touch(ticks);
@@ -67,7 +67,7 @@ namespace Assistance {
 		public double howLongButtonPressed(Gdk.Device device, uint button, long ticks, double timeOffset = 0.0)
 			{ return KeyState<uint>.Holder.howLongPressed(buttonFind(device, button), ticks, timeOffset); }
 		public double howLongButtonPressed(Gdk.Device device, uint button)
-			{ return howLongButtonPressed(device, ticks); }
+			{ return howLongButtonPressed(device, button, ticks); }
 
 		public KeyState<uint> buttonFindDefault(uint button)
 			{ return buttonFind(null, button); }
@@ -113,7 +113,7 @@ namespace Assistance {
 		public KeyHistory<uint>.Holder buttonHistoryHolder(Gdk.Device device, long ticks, double timeOffset = 0.0)
 			{ return new KeyHistory<uint>.Holder(buttonHistory(device), ticks, timeOffset); }
 		public KeyHistory<uint>.Holder buttonHistoryHolder(Gdk.Device device)
-			{ return buttonHistoryHolder(buttonHistory(device), ticks); }
+			{ return buttonHistoryHolder(device, ticks); }
 	}
 }
 
diff --git a/mono/Assistance/KeyHistory.cs b/mono/Assistance/KeyHistory.cs
index 140e9cc..ef5a0b3 100644
--- a/mono/Assistance/KeyHistory.cs
+++ b/mono/Assistance/KeyHistory.cs
@@ -51,9 +51,10 @@ namespace Assistance {
 		public KeyState<T> current
 			{ get { return states[ states.Count - 1 ]; } }
 		
-		public void change(bool press, T value, long ticks)	{
+		public KeyState<T> change(bool press, T value, long ticks)	{
 			states.Add(current.change(press, value, ticks));
 			autoRemove();
+			return current;
 		}
 		public KeyState<T> press(T value, long ticks)
 			{ return change(true, value, ticks); }
@@ -64,9 +65,9 @@ namespace Assistance {
 			// locks[a] <= ticks < locks[b]
 			int a = 0;
 			int b = states.Count - 1;
-			if (locks[a] < locks) return -1;
+			if (locks[a] < ticks) return -1;
 			if (ticks >= locks[b]) return b;
-			while(True) {
+			while(true) {
 				int c = (a + b)/2;
 				if (a == c) break;
 				if (ticks < locks[c]) b = c; else a = c;
@@ -97,8 +98,8 @@ namespace Assistance {
 			int a = 0;
 			int b = states.Count - 1;
 			if (states[a].ticks < ticks) return new KeyState<T>();
-			if (ticks >= states[b].ticks) return states[b].ticks;
-			while(True) {
+			if (ticks >= states[b].ticks) return states[b];
+			while(true) {
 				int c = (a + b)/2;
 				if (a == c) break;
 				if (ticks < states[c].ticks) b = c; else a = c;
diff --git a/mono/Assistance/Modifier.cs b/mono/Assistance/Modifier.cs
index 72630d0..c3c72bd 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, InputModifier {
+	public class Modifier: ActivePoint.Owner, InputManager.IModifier {
 		public static readonly Pen pen = new Pen("Light Gray");
 
 		public Modifier(Document document): base(document) {
@@ -21,7 +21,9 @@ namespace Assistance {
 		}
 
 		public virtual void activate() { }
-		public virtual List<Track> modify(List<Track> tracks) { return tracks; }
+		public virtual void modify(Track track, InputManager.KeyPoint keyPoint, List<Track> outTracks) { }
+		public virtual void modify(List<Track> tracks, InputManager.KeyPoint keyPoint, List<Track> outTracks)
+			{ foreach(Track track in tracks) modify(track, keyPoint, outTracks); }
 		public virtual void deactivate() { }
 
 		public virtual void draw(Cairo.Context context) { }
diff --git a/mono/Assistance/ModifierSnowflake.cs b/mono/Assistance/ModifierSnowflake.cs
index ed311e8..881794e 100644
--- a/mono/Assistance/ModifierSnowflake.cs
+++ b/mono/Assistance/ModifierSnowflake.cs
@@ -3,12 +3,38 @@ using System.Collections.Generic;
 
 namespace Assistance {
 	public class ModifierSnowflake: Modifier {
-		public static readonly int rays = 6;
-	
+		public class Modifier: Track.Modifier {
+			Point center, px, py;
+		
+			public Modifier(Track.Handler handler, Point center, double angle, bool flip):
+				base(handler)
+			{
+				this.center = center;
+				double s = Math.Sin(angle);
+				double c = Math.Cos(angle);
+				if (flip) { px = new Point(c, s); py = new Point(s,-c); }
+				     else { px = new Point(c,-s); py = new Point(s, c); }
+			}
+			
+			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);
+				Point pp = p.point.position - center;
+				p.point.position = center + new Point(Point.dot(pp, px), Point.dot(pp, py));
+				p.tangent.position = new Point(Point.dot(p.tangent.position, px), Point.dot(p.tangent.position, py));
+				return p;
+			}
+		}
+
+
 		public ActivePoint center;
+		public int rays;
 
-		public ModifierSnowflake(Document document, Point center): base(document) {
+		public ModifierSnowflake(Document document, Point center, int rays = 6): base(document) {
 			this.center = new ActivePoint(this, ActivePoint.Type.CircleCross, center);
+			this.rays = rays;
 		}
 
 		public override void draw(Cairo.Context context) {
@@ -26,25 +52,35 @@ namespace Assistance {
 				context.Restore();
 			}
 		}
-
-		public override void getTransformFuncs(List<Geometry.TransformFunc> transformFuncs) {
-			Point p0 = center.position;
-			for(int i = 0; i < rays; ++i) {
-				double angle = i*2.0*Math.PI/(double)rays;
-				double s = Math.Sin(angle);
-				double c = Math.Cos(angle);
+		
+		public override void modify(Track track, InputManager.KeyPoint keyPoint, List<Track> outTracks) {
+			if (track.handler == null) {
+				track.handler = new Track.Handler(this, track);
+				for(int i = 0; i < rays; ++i) {
+					double angle = i*2.0*Math.PI/(double)rays;
+					track.handler.tracks.Add(new Track( new Modifier(track.handler, center.position, angle, false) ));
+					track.handler.tracks.Add(new Track( new Modifier(track.handler, center.position, angle, true) ));
+				}
+			}
+			
+			outTracks.AddRange(track.handler.tracks);
+			if (!track.isChanged)
+				return;
+			
+			int start = track.points.Count - track.wayPointsAdded;
+			if (start < 0) start = 0;
+			foreach(Track subTrack in track.handler.tracks) {
+				// remove points
+				if (subTrack.points.Count < start) {
+					subTrack.points.RemoveRange(start, subTrack.points.Count - start);
+					subTrack.wayPointsRemoved += subTrack.points.Count - start;
+				}
 				
-				transformFuncs.Add(delegate(Point p) {
-					double x = p.x - p0.x;
-					double y = p.y - p0.y;
-					return p0 + new Point(c*x - s*y, s*x + c*y);
-				});
-
-				transformFuncs.Add(delegate(Point p) {
-					double x = p.x - p0.x;
-					double y = p.y - p0.y;
-					return p0 + new Point(c*x + s*y, s*x - c*y);
-				});
+				// add points
+				Track.WayPoint p0 = track.getWayPoint(start - 1);
+				for(int i = start; i < track.points.Count; ++i)
+					subTrack.points.Add( subTrack.calcWayPoint(i) );
+				subTrack.wayPointsAdded += subTrack.points.Count - start;
 			}
 		}
 	}
diff --git a/mono/Assistance/Tool.cs b/mono/Assistance/Tool.cs
index fc2f74e..2740d17 100644
--- a/mono/Assistance/Tool.cs
+++ b/mono/Assistance/Tool.cs
@@ -1,4 +1,5 @@
 using System;
+using System.Collections.Generic;
 
 namespace Assistance {
 	public class Tool {
@@ -32,7 +33,7 @@ namespace Assistance {
 		// try to merge N top painting levels and return true, or do nothing and return false
 		// was:            ------O-------O------O------
 		// become (N = 2): ------O---------------------
-		public virtual bool paintApply(int count) { return 0; }
+		public virtual int paintApply(int count) { return 0; }
 
 		// reset top level to initial state
 		// was:            ------O-------O------O------
diff --git a/mono/Assistance/Track.cs b/mono/Assistance/Track.cs
index 79dea64..66cac1f 100644
--- a/mono/Assistance/Track.cs
+++ b/mono/Assistance/Track.cs
@@ -4,13 +4,13 @@ using Assistance.Drawing;
 
 namespace Assistance {
 	public class Track {
-		public class Owner { }
+		public interface IOwner { }
 
 		public class Handler {
-			public readonly Owner owner;
+			public readonly IOwner owner;
 			public readonly Track original;
 			public readonly List<Track> tracks = new List<Track>();
-			public Handler(Owner owner, Track original) {
+			public Handler(IOwner owner, Track original) {
 				this.owner = owner;
 				this.original = original;
 			}
@@ -22,7 +22,7 @@ namespace Assistance {
 
 			public Modifier(Handler handler, double timeOffset = 0.0)
 				{ this.handler = handler; this.timeOffset = timeOffset; }
-			public Owner owner
+			public IOwner owner
 				{ get { return handler.owner; } }
 			public Track original
 				{ get { return handler.original; } }
@@ -33,12 +33,12 @@ namespace Assistance {
 		public struct Point {
 			public Assistance.Point position;
 			public double pressure;
-			public Point tilt;
+			public Assistance.Point tilt;
 	
 			public Point(
 				Assistance.Point position,
 				double pressure,
-				Point tilt
+				Assistance.Point tilt
 			) {
 				this.position = position;
 				this.pressure = pressure;
@@ -51,10 +51,10 @@ namespace Assistance {
 				{ return new Point(a.position - b.position, a.pressure - b.pressure, a.tilt - b.tilt); }
 			public static Point operator* (Point a, double b)
 				{ return new Point(a.position*b, a.pressure*b, a.tilt*b); }
-			public static Point operator* (double b, Point a)
+			public static Point operator* (double a, Point b)
 				{ return a*b; }
 			public static Point operator/ (Point a, double b)
-				{ return this*(1.0/b); }
+				{ return a*(1.0/b); }
 	
 			public bool isEqual(Point other) {
 				return position.isEqual(other.position)
@@ -129,6 +129,7 @@ namespace Assistance {
 		
 		public Track(Modifier modifier):
 			this( modifier.original.device,
+				  modifier.original.touchId,
 				  modifier.original.keyHistory.offset( modifier.timeOffset ),
 				  modifier.original.buttonHistory.offset( modifier.timeOffset ) )
 			{ this.modifier = modifier; }
@@ -235,7 +236,7 @@ namespace Assistance {
 		
 		public WayPoint interpolate(double index) {
 			double frac;
-			WayPoint p0 = floorIndex(index, out frac);
+			WayPoint p0 = floorWayPoint(index, out frac);
 			WayPoint p1 = ceilWayPoint(index);
 			return interpolate(p0, p1, frac);
 		}