public static PtzVec<Slider> GetLvlSliders(PtzView view) {
				return Ptz.Vec(
					pan: view.sliderContPanVelocity,
					tilt: view.sliderContTiltVelocity,
					zoom: view.sliderContZoomVelocity
				);
			}
			public static PtzVec<Slider> GetPosSliders(PtzView view) {
				return Ptz.Vec(
					pan: view.sliderAbsPanValue,
					tilt: view.sliderAbsTiltValue,
					zoom: view.sliderAbsZoomValue
				);
			}
			public static PtzVec<Slider> GetSpeedSliders(PtzView view) {
				return Ptz.Vec(
					pan: view.sliderAbsPanSpeed,
					tilt: view.sliderAbsTiltSpeed,
					zoom: view.sliderAbsZoomSpeed
				);
			}
			public static PtzVec<Slider> GetStepSliders(PtzView view) {
				return Ptz.Vec(
					pan: view.sliderRelPanValue,
					tilt: view.sliderRelTiltValue,
					zoom: view.sliderRelZoomValue
				);
			}
			public static PtzVec<Tuple<FloatRange, float>> GetSpeedInfo(PtzView view) {
				Tuple<FloatRange, float> pan = null;
				Tuple<FloatRange, float> tilt = null;
				Tuple<FloatRange, float> zoom = null;

				var defSpeeds = view.ptzConfig.defaultPTZSpeed;
				if (defSpeeds == null) {
					return Ptz.Vec(pan, tilt, zoom);
				}

				var panTiltDef = defSpeeds.panTilt;
				if (panTiltDef != null) {
					var panTiltSpace = view.ptzSpacesConfig.absRelPanTiltSpeed;
					var rng = panTiltSpace != null ? panTiltSpace.xRange : null;
					pan = Tuple.Create(rng, panTiltDef.x);
					tilt = Tuple.Create(rng, panTiltDef.y);
				}

				var zoomDef = defSpeeds.zoom;
				if (zoomDef != null) {
					var zoomSpace = view.ptzSpacesConfig.absRelZoomSpeed;
					var rng = zoomSpace != null ? zoomSpace.xRange : null;
					zoom = Tuple.Create(rng, zoomDef.x);
				}
				return Ptz.Vec(pan, tilt, zoom);
			}
			public static AbsRelSpeed Create(PtzAxis ax, PtzView view, Slider slider) {
				AbsRelSpeed res = null;
				do {
					var spdInf = GetSpeedInfo(view)[ax];
					if (spdInf == null) {
						break;
					}
					var range = spdInf.Item1;
					if (range == null) {
						break;
					}
					var def = spdInf.Item2;
					if (range == null) {
						break;
					}
					if (float.IsNaN(def)) {
						break;
					}
					var min = range.min;
					var max = range.max;
					if (float.IsNaN(min) || float.IsNaN(max) || min > max) {
						break;
					}
					if (float.IsNegativeInfinity(min)) {
						min = float.MinValue;
					}
					if (float.IsPositiveInfinity(max)) {
						max = float.MaxValue;
					}
					if (def > max || def < min) {
						res = new AbsRelSpeed(def, def, def);
						break;
					}
					res = new AbsRelSpeed(min, max, def);
					if (slider != null) {
						slider.Minimum = min;
						slider.Maximum = max;
						slider.SmallChange = (max - min) / 100f;
						slider.LargeChange = (max - min) / 10f;
						slider.Value = def;
						slider.Visibility = Visibility.Visible;
						if (min != max) {
							slider.IsEnabled = true;
							slider.ValueChanged += (s, a) => {
								res.val = res.rng.Coerce((float)a.NewValue);
							};
						} else {
							slider.IsEnabled = false;
						}
					}
					return res;
				} while (false);

				if (slider != null) {
					slider.Visibility = Visibility.Collapsed;
				}
				return res;
			}
			public static AbsMov Setup(PtzAxis ax, PtzView view) {
				AbsMov res = null;
				var posSlider = GetPosSliders(view)[ax];
				var speedSlider = GetSpeedSliders(view)[ax];
				do {
					var range = GetPosRanges(view)[ax];
					if (range == null) {
						break;
					}
					var min = range.min;
					var max = range.max;
					if (float.IsNaN(min) || float.IsNaN(max) || min > max) {
						break;
					}
					if (float.IsNegativeInfinity(min)) {
						min = float.MinValue;
					}
					if (float.IsPositiveInfinity(max)) {
						max = float.MaxValue;
					}
					if (posSlider == null) {
						res = new AbsMov(min, max, AbsRelSpeed.Create(ax, view, null));
						break;
					}
					res = new AbsMov(min, max, AbsRelSpeed.Create(ax, view, speedSlider));
					posSlider.Minimum = min;
					posSlider.Maximum = max;
					posSlider.SmallChange = (max-min)/100f;
					posSlider.LargeChange = (max-min)/10f;
					posSlider.Value = res.pos;
					posSlider.Visibility = Visibility.Visible;
					if (min != max) {
						posSlider.IsEnabled = true;
						posSlider.ValueChanged += (s, a) => {
							res.pos = res.rng.Coerce((float)a.NewValue);
						};
					} else {
						posSlider.IsEnabled = false;
					}
					return res;
				} while (false);

				if (posSlider != null) {
					posSlider.Visibility = Visibility.Collapsed;
				}
				if (speedSlider != null) {
					speedSlider.Visibility = Visibility.Collapsed;
				}

				return res;
			}
			public static RelMov Setup(PtzAxis ax, PtzView view) {
				RelMov res = null;
				var stepSlider = GetStepSliders(view)[ax];
				var sppedSlider = GetSpeedSliders(view)[ax];
				do {
					var range = GetValueRanges(view)[ax];
					if (range == null) {
						break;
					}
					var min = range.min;
					var max = range.max;
					if (float.IsNaN(min) || float.IsNaN(max) || min > max) {
						break;
					}
					if (float.IsNegativeInfinity(min)) {
						min = float.MinValue;
					}
					if (float.IsPositiveInfinity(max)) {
						max = float.MaxValue;
					}
					if (stepSlider == null) {
						res = new RelMov(min, max, AbsRelSpeed.Create(ax, view, null));
						break;
					}
					res = new RelMov(min, max, AbsRelSpeed.Create(ax, view, sppedSlider));
					stepSlider.Minimum = 0d;
					stepSlider.Maximum = 100d;
					stepSlider.SmallChange = 1d;
					stepSlider.LargeChange = 10d;
					stepSlider.Value = res.step;
					stepSlider.Visibility = Visibility.Visible;
					if (min != max) {
						stepSlider.IsEnabled = true;
						stepSlider.ValueChanged += (s, a) => {
							res.step = (float)a.NewValue;
						};
					} else {
						stepSlider.IsEnabled = false;
					}
					return res;
				} while(false);

				if (stepSlider != null) {
					stepSlider.Visibility = Visibility.Collapsed;
				}
				if (sppedSlider != null) {
					sppedSlider.Visibility = Visibility.Collapsed;
				}

				return res;
			}
			public static PtzVec<FloatRange> GetVelRanges(PtzView view) {
				FloatRange pan, tilt, zoom;

				var panTiltSpace = view.ptzSpacesConfig.contPanTiltVelocity;
				var zoomSpace = view.ptzSpacesConfig.contZoomVelocity;

				if (panTiltSpace != null) {
					pan = panTiltSpace.xRange; tilt = panTiltSpace.yRange;
				} else {
					pan = tilt = null;
				}
				zoom = zoomSpace != null ? zoomSpace.xRange : null;
				return Ptz.Vec(pan, tilt, zoom);
			}
			public static PtzVec<FloatRange> GetPosRanges(PtzView view) {
				FloatRange pan, tilt, zoom;

				var panTiltSpace = view.ptzSpacesConfig.absPanTiltPosition;
				var zoomSpace = view.ptzSpacesConfig.absZoomPosition;

				if (panTiltSpace != null) {
					pan = panTiltSpace.xRange; tilt = panTiltSpace.yRange;
				} else {
					pan = tilt = null;
				}
				zoom = zoomSpace != null ? zoomSpace.xRange : null;
				return Ptz.Vec(pan, tilt, zoom);
			}
			public static ContMov Setup(PtzAxis ax, PtzView view) {
				ContMov res = null;
				var lvlSlider = GetLvlSliders(view)[ax];
				do {
					var range = GetVelRanges(view)[ax];
					if (range == null) {
						break;
					}
					var min = range.min;
					var max = range.max;
					if (float.IsNaN(min) || float.IsNaN(max) || min > max) {
						break;
					}
					if (float.IsNegativeInfinity(min)) {
						min = float.MinValue;
					}
					if (float.IsPositiveInfinity(max)) {
						max = float.MaxValue;
					}
					res = new ContMov(min, max);
					if (lvlSlider != null) {
						lvlSlider.Minimum = 0d;
						lvlSlider.Maximum = 100d;
						lvlSlider.SmallChange = 1d;
						lvlSlider.LargeChange = 10d;
						lvlSlider.Value = res.level;
						lvlSlider.Visibility = Visibility.Visible;
						if (min != max) {
							lvlSlider.IsEnabled = true;
							lvlSlider.ValueChanged += (s, a) => {
								res.level = (float)a.NewValue;
							};
						} else {
							lvlSlider.IsEnabled = false;
						}
					}
					return res;
				} while (false);

				if (lvlSlider != null) {
					lvlSlider.Visibility = Visibility.Collapsed;
				}

				return res;
			}