function uiScrollClass( id, forcedInit){
	// must make event handler to activate or deactivate scroll control
	var c1=jml.obj,c2=jml.xml.node,c3=jml.events,c4=jml.jme;
	var host,intl,item={box:null,mask:null,content:null,node:null,step:null,loop:null,active:false},jme1=new jml.jme.motion();
	var firstRun = true;
	var forcedInit = forcedInit || false;

	function init(){
		var o=getObj(id);
		if(!isset(o)) return;
		item.box=o;
		item.mask=c2.byPath('0',o);
		item.content=c2.byPath('0.0',o);
		call(host.onInit,[]);
		calculate();
		if(!isset(item.node)) item.node={x:c2.byPath('0.0.0',item.content),y:c2.byPath('0.0',item.content)};
		if(!isset(item.step)) item.step={x:0,y:0};		
		
		if(isset(host.textContainerId)){
			var o1=getObj(host.textContainerId);
			if(isset(o1)) c3.add(o1,'__textResize',calculate);
		}
	}
	function setToInitial(){
		if(isset(host.selectedIndex)&&isset(host.initialAxis)){
			
			var o=getObj(id);
			if(!isset(o)) return;
			item.box=o;
			item.mask=c2.byPath('0',o);
			item.content=c2.byPath('0.0',o);			
			if(!isset(item.node)) item.node={x:c2.byPath('0.0.0',item.content),y:c2.byPath('0.0',item.content)};
			if(!isset(item.step)) item.step={x:0,y:0};					
		
			var s1=host.initialAxis;
			if(s1=='x'||s1=='y'){
				var x0=s1=='x'?c2.byPath('0.0',item.content):c2.byPath('0',item.content);
				
				var n1= c2.length(x0);
				var n2= host.selectedIndex;
				var n3= host.visualNumber;
				if(!isset(n3)) n3=0;
				n2=n2-1;				
				
				if(n2>=n1-n3) n2=n1-(n3);
				if(n2<0) n2=0;

				var x1=c2.byPosition(n2,x0);
				var x2=c2.byPosition(0,x0);
				
				if(isset(x1)){
					var n4=getDistance(x1,x2,s1,1);
					var n5=c1.get(item.content,'left');
					var n6=c1.get(item.mask,'offsetWidth');
					var n7=c1.get(item.content,'offsetWidth');
					
					var n8=0+n6-n7;
					var n9=n5-n4;
					if(n9<n8) n9 = n8;
					c1.set(item.content,'left',(n9+1)+"px");
					item.node[s1]=x1;
				}
			}
		}		
	}
	function run(b,l,a,d,v,t,e){
		var b=b,l=l,a=a,d=d,v=v||1,t=isset(t)?t:b?20:5,e=e||'noEase';
		clear();
		if(a!='x'&&a!='y'){
			host.stop();
			return;
		}
		if(!isset(item.node)) item.node={x:c2.byPath('0.0.0',item.content),y:c2.byPath('0.0',item.content)};
		if(!isset(item.step)) item.step={x:0,y:0};
		var p2=getP(item.content);
		if(l&&!isset(item.loop)){
			if(!isset(item.loop)) item.loop={step:{x:null,y:null},scroll:{x:null,y:null}};
			item.loop.step={x:c2.length(item.node.y),y:c2.length(c2.parent(item.node.y,1))};
			item.loop.scroll={x:p2.w,y:p2.h};
			duplicate(c2.parent(item.node.y,1),item.loop.step);			
		}else{
			if(!l&&isset(item.loop)){
			
				// clear and set position to current element (event if emulated...)
				// this is equivalent to reset when i do not try to research the current position...
				// also need to set item.step[a] to firstchild....

				var n1=item.loop.scroll[a]+p2[a];
				remove(c2.parent(item.node.y,1),item.loop.step);
				item.loop=null;
				
				//c1.set(item.content,'left','0px;');
				//c1.set(item.content,'top','0px;');
				
			}
		}
		var s1=a=='x'?'w':'h',s2=a=='x'?'left':'top';
		var p1=getP(item.mask),p2=getP(item.content);
		if(!isset(s1)||p1[s1]>=p2[s1]){
			if(p2[a]!=0) c1.set(item.content,s2,'0px');
			return;
		}
		if(b){
			if(!item.active){
				item.active=true;
				var x0=a=='x'?item.node.y:c2.parent(item.node.y,1),n1=c2.position(item.node[a]),n2=c2.length(x0),n3=Math.min(v,n2-(n1+(d*v))),n4=n1+(d*n3)+item.step[a];
				if(n4<0) n4=0;
				if(n3==0){
					item.active=false;
					return;
				}
				var x1=c2.byPosition(n4,x0);
				if(item.step[a]!=0&&x1!=item.node[a]) item.step[a]=0;
				if(n3>0&&n3<v) item.step[a]=v-n3;
				if(isset(x1)&&x1!=item.node[a]){
					var n5=getDistance(x1,item.node[a],a,d);
					item.node[a]=x1;
					jme1.start({target:item.content,property:s2,start:p2[a],end:p2[a]-n5,duration:t,equation:e,id:null});
					jme1.onMotionFinished=function(t,p){
						item.active=false;
						if(isset(host.onScrollFinished)){
							host.onScrollFinished(n4, n2-1); // patch...
							
						}
					}
					jme1.onMotion=function(t,p){}
				}else{
					item.active=false;
				}
			}
		}else{
			intl=setInterval(function(){
				var p1=getP(item.mask),p2=getP(item.content),n1=p2[a]-(d*t);
				if((d==1&&n1>=(l?0-item.loop.scroll[a]:p1[a]+p1[s1]-p2[s1]-2))||(d==-1&&n1<=0)){
					c1.set(item.content,s2,n1+'px');
				}else{
					l?c1.set(item.content,s2,(d==1?0:0-item.loop.scroll[a])+'px'):host.stop();
				}
			},10);
		}
	}
	function calculate(){
		var o1=item.content,o2=item.mask;
		var s1=host.maskExpandAxis;
		if(isset(s1)&&isset(o1)&&isset(o2)){
			var s2 = s1 == 'y' ? 'height' : s1=='x' ? 'width' : null ;
			if(isset(s2)) c1.set(o2,'height',c1.get(o1,'offset'+ucFirst(s2))+'px');
		}
	}
	function duplicate(x,o){
		for(var i=0;i<o.y;i++){
			var x1=c2.byPosition(i,x);
			for(var j=0;j<o.x;j++) var x3=c2.duplicate(c2.byPosition(j,x1));
			var x2=c2.duplicate(x1);
		}
	}
	function remove(x,o){
		for(var i=c2.length(x)-1;i>=0;i--){
			var x1=c2.byPosition(i,x);
			if(i>=o.y){
				c2.remove(x1);
			}else{
				for(var j=c2.length(x1)-1;j>=o.x;j--) c2.remove(c2.byPosition(j,x1));			
			}
		}	
	}
	function getDistance(x1,x2,s,d){
		var x3=c2.parent(x1,1),n1=c2.position(x1),n2=c2.position(x2),n3=Math.abs(n1-n2),n4=0;
		for(var i=0;i<n3;i++){
			n4+=c1.get(c2.byPosition(i,x3),'offset'+(s=='x'?'Width':'Height'));
		}
		return n4*d;
	}
	function clear(){clearInterval(intl);}
	function getP(o){
		var a1=['left','top','width','height'];
		var a2=[c1.get(o,a1[0]),c1.get(o,a1[1]),c1.get(o,a1[2]),c1.get(o,a1[3])];
		for(var i=0;i<a2.length;i++){ if(a2[i]=='auto') a2[i]=i>1?c1.get(o,'offset'+ucFirst(a1[i])):0; }
		return {x:a2[0],y:a2[1],w:a2[2],h:a2[3]};
	}	
	return {
		$:function(){
			host=this;
			if( forcedInit ){
				init();
			}else{
				c3.add(window,'load',init);
				c3.add(window,'resize',host.reCalibrate);
			}
			return this;
		},
		onScrollFinished:null,
		onScrollLooped:null,
		onScroll:null,
		onInit:null,
		maskExpandAxis:'y',
		textContainerId:null,
		reCalibrate:calculate,
		selectedIndex:null,
		initialAxis:'x',
		visualNumber:null,
		initialize:setToInitial,
		reset:function(){
			item.content=c2.byPath('0.0',item.box);
			if(isset(item.content)){
				calculate();			
				//c1.set(item.content,'left','0px;');
				//c1.set(item.content,'top','0px;');
				item.node=null;
				item.step=null;
			}
		},
		start:{
			step:function(a,d,v,t,e,l){ run(true,l||false,a,d,v,t,e); },
			scroll:function(a,d,t,l){ run(false,l||false,a,d,null,t); },
			auto:function(axis, direction, speed, loop){},	// in dev...
			yoyo:function(axis, startDirection, speed, loop){}	// in dev...
		},
		stop:clear
	}.$();
}