text: //	var Klass=require("../lib/Klass");
  const R=require("../lib/R");
  module.exports=function (Tonyu) {
  	var cnts={enterC:{},exitC:0};
  	var idSeq=1;
  	//try {window.cnts=cnts;}catch(e){}
  	class TonyuThread {
  		constructor() {
  			this.frame=null;
  			this._isDead=false;
  			//this._isAlive=true;
  			this.cnt=0;
  			this._isWaiting=false;
  			this.fSuspended=false;
  			this.tryStack=[];
  			this.preemptionTime=60;
  			this.onEndHandlers=[];
  			this.onTerminateHandlers=[];
  			this.id=idSeq++;
  			this.age=0; // inc if object pooled
  		}
  		isAlive() {
  			return !this.isDead();
  			//return this.frame!=null && this._isAlive;
  		}
  		isDead() {
  			this._isDead=this._isDead || (this.frame==null) ||
  			(this._threadGroup && (
  					this._threadGroup.objectPoolAge!=this.tGrpObjectPoolAge ||
  					this._threadGroup.isDeadThreadGroup()
  			));
  			return this._isDead;
  		}
  		setThreadGroup(g) {// g:TonyuThread
  			this._threadGroup=g;
  			this.tGrpObjectPoolAge=g.objectPoolAge;
  			//if (g) g.add(fb);
  		}
  		isWaiting() {
  			return this._isWaiting;
  		}
  		suspend() {
  			this.fSuspended=true;
  			this.cnt=0;
  		}
  		enter(frameFunc) {
  			//var n=frameFunc.name;
  			//cnts.enterC[n]=(cnts.enterC[n]||0)+1;
  			this.frame={prev:this.frame, func:frameFunc};
  		}
  		apply(obj, methodName, args) {
  			if (!args) args=[];
  			var method;
  			if (typeof methodName=="string") {
  				method=obj["fiber$"+methodName];
  				if (!method) {
  					throw new Error(R("undefinedMethod",methodName));
  				}
  			}
  			if (typeof methodName=="function") {
  				method=methodName.fiber;
  				if (!method) {
  					var n=methodName.methodInfo ? methodName.methodInfo.name : methodName.name;
  					throw new Error(R("notAWaitableMethod",n));
  				}
  			}
  			args=[this].concat(args);
  			var pc=0;
  			return this.enter(function (th) {
  				switch (pc){
  				case 0:
  					method.apply(obj,args);
  					pc=1;break;
  				case 1:
  					th.termStatus="success";
  					th.notifyEnd(th.retVal);
  					args[0].exit();
  					pc=2;break;
  				}
  			});
  		}
  		notifyEnd(r) {
  			this.onEndHandlers.forEach(function (e) {
  				e(r);
  			});
  			this.notifyTermination({status:"success",value:r});
  		}
  		notifyTermination(tst) {
  			this.onTerminateHandlers.forEach(function (e) {
  				e(tst);
  			});
  		}
  		on(type,f) {
  			if (type==="end"||type==="success") this.onEndHandlers.push(f);
  			if (type==="terminate") {
  				this.onTerminateHandlers.push(f);
  				if (this.handleEx) delete this.handleEx;
  			}
  		}
  		promise() {
  			var fb=this;
  			return new Promise(function (succ,err) {
  				fb.on("terminate",function (st) {
  					if (st.status==="success") {
  						succ(st.value);
  					} else if (st.status==="exception"){
  						err(st.exception);
  					} else {
  						err(new Error(st.status));
  					}
  				});
  			});
  		}
  		then(succ,err) {
  			if (err) return this.promise().then(succ,err);
  			else return this.promise().then(succ);
  		}
  		fail(err) {
  			return this.promise().then(e=>e, err);
  		}
  		gotoCatch(e) {
  			var fb=this;
  			if (fb.tryStack.length==0) {
  				fb.termStatus="exception";
  				fb.kill();
  				if (fb.handleEx) fb.handleEx(e);
  				else fb.notifyTermination({status:"exception",exception:e});
  				return;
  			}
  			fb.lastEx=e;
  			var s=fb.tryStack.pop();
  			while (fb.frame) {
  				if (s.frame===fb.frame) {
  					fb.catchPC=s.catchPC;
  					break;
  				} else {
  					fb.frame=fb.frame.prev;
  				}
  			}
  		}
  		startCatch() {
  			var fb=this;
  			var e=fb.lastEx;
  			fb.lastEx=null;
  			return e;
  		}
  		exit(res) {
  			//cnts.exitC++;
  			this.frame=(this.frame ? this.frame.prev:null);
  			this.retVal=res;
  		}
  		enterTry(catchPC) {
  			var fb=this;
  			fb.tryStack.push({frame:fb.frame,catchPC:catchPC});
  		}
  		exitTry() {
  			var fb=this;
  			fb.tryStack.pop();
  		}
  		waitEvent(obj,eventSpec) { // eventSpec=[EventType, arg1, arg2....]
  			var fb=this;
  			fb.suspend();
  			if (!obj.on) return;
  			var h;
  			eventSpec=eventSpec.concat(function () {
  				fb.lastEvent=arguments;
  				fb.retVal=arguments[0];
  				h.remove();
  				fb.steps();
  			});
  			h=obj.on.apply(obj, eventSpec);
  		}
  		runAsync(f) {
  			var fb=this;
  			var succ=function () {
  				fb.retVal=arguments;
  				fb.steps();
  			};
  			var err=function () {
  				var msg="";
  				for (var i=0; i<arguments.length; i++) {
  					msg+=arguments[i]+",";
  				}
  				if (msg.length==0) msg="Async fail";
  				var e=new Error(msg);
  				e.args=arguments;
  				fb.gotoCatch(e);
  				fb.steps();
  			};
  			fb.suspend();
  			setTimeout(function () {
  				f(succ,err);
  			},0);
  		}
  		waitFor(j) {
  			var fb=this;
  			fb._isWaiting=true;
  			fb.suspend();
  			if (j instanceof TonyuThread) j=j.promise();
  			return Promise.resolve(j).then(function (r) {
  				fb.retVal=r;
  				fb.stepsLoop();
  			}).then(e=>e,function (e) {
  				fb.gotoCatch(fb.wrapError(e));
  				fb.stepsLoop();
  			});
  		}
  		wrapError(e) {
  			if (e instanceof Error) return e;
  			var re=new Error(e);
  			re.original=e;
  			return re;
  		}
  		resume(retVal) {
  			this.retVal=retVal;
  			this.steps();
  		}
  		steps() {
  			var fb=this;
  			if (fb.isDead()) return;
  			var sv=Tonyu.currentThread;
  			Tonyu.currentThread=fb;
  			fb.cnt=fb.preemptionTime;
  			fb.preempted=false;
  			fb.fSuspended=false;
  			while (fb.cnt>0 && fb.frame) {
  				try {
  					//while (new Date().getTime()<lim) {
  					while (fb.cnt-->0 && fb.frame) {
  						fb.frame.func(fb);
  					}
  					fb.preempted= (!fb.fSuspended) && fb.isAlive();
  				} catch(e) {
  					fb.gotoCatch(e);
  				}
  			}
  			Tonyu.currentThread=sv;
  		}
  		stepsLoop() {
  			var fb=this;
  			fb.steps();
  			if (fb.preempted) {
  				setTimeout(function () {
  					fb.stepsLoop();
  				},0);
  			}
  		}
  		kill() {
  			var fb=this;
  			//fb._isAlive=false;
  			fb._isDead=true;
  			fb.frame=null;
  			if (!fb.termStatus) {
  				fb.termStatus="killed";
  				fb.notifyTermination({status:"killed"});
  			}
  		}
  		clearFrame() {
  			this.frame=null;
  			this.tryStack=[];
  		}
  	}
  	return TonyuThread;
  };
  