
void podgotovka(SYS){
	SYS->functions=(map){};
	if(isset(SYS->filename))filename=SYS->filename; else filename=getThisFileName();
	params={"toString","priznakfinish","control","compare","correctir"};
	for(i=0;i<params.size();++i)if(SYS->isset(params[i]))
		SYS->functions[params[i]]=getFunction((*SYS)[params[i]],filename);
	SYS->functions.methods={};
	if(isset(SYS->methods)){
		for(i=0;i<SYS->methods.length();++i)SYS->functions.methods.push(
			getFunction(SYS->methods[i],filename)
			);
		}
	SYS->functions.parameters={};
	if(isset(SYS->parameters)){
		for(i=0;i<SYS->parameters.length();++i)SYS->functions.parameters.push(
			getFunction(SYS->parameters[i],filename)
			);
		}
	if(!isset(SYS->pirmision))SYS->pirmision=(map)0;
	if(!SYS->pirmision.isset("prosmotr-new"))SYS->pirmision["prosmotr-new"]=0;
}


var poisk(SYS){
	if(!isset(SYS->functions))podgotovka(SYS);
	b=1;
	if(isset(SYS->namemodele)){
		str=SYS->namemodele;
		if(isset(SYS->ver))str+=SYS->ver;
		b=include(WAY+"\\code\\Deployment\\Buffer\\"+str+".txt");
		}
	if(!b){
		LoadSystem(SYS);
		k=SYS->k;
		if(SYS->good)return 1;
		if(isset(SYS->filename)){
			s=SYS->filename;
			s=s.substr(WAY.length()+1);
			if(isset(SYS->predoxranitelfilename))if(s!=SYS->predoxranitelfilename){
				trace("Поменяйте имя модели 'namemodele' или версию 'ver'.");
				return 0;
				}
			}
		}else{
		SYS->m={SYS->starter};
		SYS->timezatratil=0;
		SYS->G=(graf)0;
		SYS->G.MARKER(0,0,"",0,"START");
		k=0;
		}
	good=1;
	timeLabel=starttime=getTime();
	while(k<SYS->m.size()){
		X=&SYS->m[k];
		if(isset(SYS->functions.control)){
			f=SYS->functions.control;
			if(!f.run(X)){
				SYS->G.MARKER(k,0,"",0,"END");
				++k;
				continue;
				}
			}
		for(i=0;i<SYS->functions.methods.size();++i){
			methodX=SYS->functions.parameters[i];
			args=methodX.run(X);
			//name=SYS->methods[i];
			methodX=SYS->functions.methods[i];
			for(j=0;j<args.size();++j){
				Y=*X;
				methodX.run1({&Y}+args[j]);
				if(addUnitX(SYS,&Y,k))break 3;//return;
				}
			}
		++k;
		if(isset(SYS->timeLimitForSave))
		if(getTime()-timeLabel>=SYS->timeLimitForSave){
			SYS->k=k;
			SYS->good=0;
			SYS->timezatratil+=getTime()-timeLabel;
			UnloadSystem(SYS);
			timeLabel=getTime();
			trace("Текущее состояние системы разворачивания сохранено.");
			}
		if(isset(SYS->timeborder))
		if(getTime()-starttime>=SYS->timeborder){
			good=0;
			break;
			}
		}
	SYS->k=k;
	SYS->good=good;
	SYS->timezatratil+=getTime()-timeLabel;
	UnloadSystem(SYS);
	if(good)SYS->tolkochto=1;
	return good; // пригодно для анализа...
}


string getAuthorForm(X){
	t=typeof(*X);
	if(t=="map"){
		s="{";
		keys=X->getKeys();
		for(i=0;i<keys.size();++i){
			if(i)s+=",";
			s+=keys[i];
			s+=":";
			s+=getAuthorForm(&(*X)[keys[i]]);
			}
		s+="}";
		return s;
		}
	if(t=="vector"){
		s="{";
		for(i=0;i<X->size();++i){
			if(i)s+=",";
			s+=getAuthorForm(&(*X)[i]);
			}
		s+="}";
		return s;
		}
	if(t=="string")return X->export();
	return *X;
}


var printer(SYS){
	R="";
	fine={};
	nets=SYS->G.getMARKER(#,0,"",0,"FINISH");
	for(i=0;i<nets.size();++i)fine.push(nets[i][0]);
	zapret={};
	nets=SYS->G.getMARKER(#,0,"",0,"END");
	for(t=0;t<nets.size();++t)zapret.push(nets[t][0]);
	n=((string)SYS->m.size()).length();
	for(i=0;i<SYS->m.size();++i){
		str=(string)i;
		while(str.length()<n)str="0"+str;
		str+=") ";
		if(isset(SYS->functions.toString))str+=SYS->functions.toString.run(&SYS->m[i]);
			else str+=getAuthorForm(&SYS->m[i]);
		str+=" ";
		if(!i)str+="старт ";
		if(fine.indexOf(i)>=0)str+="финиш ";
		if(zapret.indexOf(i)>=0)str+="недопустимо ";
		nets=SYS->G.getNET(i,0,"",1,#);
		go={};
		for(t=0;t<nets.size();++t)go.push(nets[t][0]);
		if(go.size())str+=go.export();
		str+="\n";
		R+=str;
		}
	return R;
}


bool addUnitX(SYS,X,n){
	for(i=0;i<SYS->m.size();++i){
		if(isset(SYS->functions.compare)){
			if(SYS->functions.compare.run(&SYS->m[i],X))break;
			} else
		if(SYS->m[i]==*X)break;
		}
	okadd=0;
	if(i==SYS->m.size()){
		SYS->m.push(*X);
		if(SYS->pirmision["prosmotr-new"]){
			ok=0;
			if(isset(SYS->functions.control)){
				f=SYS->functions.control;
				if(!f.run(X))ok=1;
				}
			trace(getAuthorForm(X)+(ok?" тупик":""));
			}
		okadd=1;
		}else{
		if(!SYS->G.getNET(n,0,"",1,i).size())okadd=1;
		}
	if(okadd)SYS->G.NET(n,0,"",1,i);
	b=0;
	if(isset(SYS->functions.priznakfinish))
	if(b=SYS->functions.priznakfinish.run(X)){
		SYS->G.MARKER(i,0,"",0,"FINISH");
		if(b)if(isset(SYS->firstFineEndOK))if(SYS->firstFineEndOK)return 1;
		}
	return 0;
}


void FindWAYS(SYS,NxFinish){
	if(isset(SYS->tableWAY))return;
	G=&SYS->G;
	a=G->getMARKER(#,0,"",0,"START")[0][0];
	b={};
	if(isset(NxFinish)){
		if(typeof(NxFinish)=="vector")b=NxFinish; else b={NxFinish};
		} else {
		bb=G->getMARKER(#,0,"",0,"FINISH");
		for(i=0;i<bb.size();++i)b.push(bb[i][0]);
		}
	if(!b.size())return;
	q=G->getUnits();
	m=(map)0;
	for(i=0;i<q.size();++i)m[q[i]]=0;
	m[a]=n=1;
	xb=-1;
	while(1){
		for(i=0;i<b.size();++i)if(m[b[i]]){
			xb=b[i];
			break 2;
			}
		ok=0;
		for(i=0;i<q.size();++i)if(m[q[i]]==n){
			W=G->getNET(q[i],0,#,1,#);
			for(t=0;t<W.size();++t){
				k=W[t][1];
				if(!m[k]){
					m[k]=n+1;
					ok=1;
					}
				}
			}
		++n;
		if(!ok)break;
		}
	n=m[xb];
	if(!n)return;
	m2=(map)0;
	for(i=0;i<b.size();++i)m2[b[i]]=n;
	while(n>1){
		for(i=0;i<q.size();++i)if(m[q[i]]==n && m2.isset(q[i])){
			W=G->getNET(#,0,#,1,q[i]);
			for(t=0;t<W.size();++t){
				k=W[t][0];
				if(m[k]==n-1)m2[k]=n-1;
				}
			}
		--n;
		}
	SYS->tableWAY=m2;
}


var DefineRandomWAY(SYS){
	if(!isset(SYS->tableWAY))return;
	G=&SYS->G;
	table=&SYS->tableWAY;
	q=SYS->tableWAY.getKeys();
	m={};
	pos=n=1;
	for(i=0;i<q.size();++i)if((*table)[q[i]]==n){
		n=q[i];
		break;
		}
	while(1){
		m.push(n);
		++pos;
		next={};
		W=G->getNET(n,0,#,1,#);
		for(t=0;t<W.size();++t){
			k=W[t][1];
			if(isset((*table)[k]))if((*table)[k]==pos)next.push(k);
			}
		if(!next.size())break;
		x=rand()%next.size();
		n=next[x];
		}
	return m;
}


var GetAllWaysForUnitN(SYS,NxFinish){
	FindWAYS(SYS,NxFinish);
	if(!isset(SYS->tableWAY))return;
	G=&SYS->G;
	table=&SYS->tableWAY;
/*
	q=SYS->tableWAY.getKeys();
	n=1;
	for(i=0;i<q.size();++i)if((*table)[q[i]]==n){
		n=q[i];
		break;
		}
	// n - start unit number
*/
	n=0;
	ways={};
	SubGetAllWaysForUnitN(&ways,G,table,{},n);
	return ways;
}


void SubGetAllWaysForUnitN(ways,G,table,way,n){
	way.push(n);
	pos=way.size()+1;
	next={};
	W=G->getNET(n,0,#,1,#);
	for(t=0;t<W.size();++t){
		k=W[t][1];
		if(isset((*table)[k]))if((*table)[k]==pos)next.push(k);
		}
	if(!next.size()){
		ways->push(way);
		return;
		}
	for(t=0;t<next.size();++t)SubGetAllWaysForUnitN(ways,G,table,way,next[t]);
}




var printWAY(SYS,way){
	ok=1;
	if(!isset(way))ok=0;
	if(ok)if(!way.size())ok=0;
	if(!ok)return "Нет пути трансформации заданной системы.";
	f=0;
	fzadan=0;
	if(isset(SYS->functions.toString)){
		fzadan=1;
		f=SYS->functions.toString;
		}
	first=1;
	row={};
	for(i=0;i<way.size();++i){
		n=way[i];
		R="";
		acces=&SYS->m[n];
		if(isset(SYS->functions.correctir)){
			if(first){
				first=0;
				PREV=*acces;
				}else{
				SYS->functions.correctir.run(&PREV,*acces);
				acces=&PREV;
				}
			}
		if(fzadan)R+=f.run(acces); else R+=getAuthorForm(acces);
		R+="\n";
		row.push(R);
		}
	formatZvitov=0;
	if(isset(SYS->formatZvitov))formatZvitov=SYS->formatZvitov;
	if(formatZvitov)return getzvit(row);
	str="";
	for(i=0;i<row.length();++i)str+=row[i];
	return str;
}


void Prorabotka(SYS,f){
	mp=reserve(SYS->m.size());
	iterator=1;
	n=1;
	while(n){
		n=0;
		for(i=0;i<mp.size();++i)if(!mp[i]){
			nets=SYS->G.getNET(i,0,"",1,#);
			ok=1;
			S={};
			for(j=0;j<nets.size();++j){
				p=nets[j][0];
				S.push(&SYS->m[p]);
				if(!mp[p])ok=0;
				}
			if(!ok)continue;
			f.run(&SYS->m[i],S);
			mp[i]=iterator;
			++n;
			}
		++iterator;
		//tracex(n," ");
		}
}



void UstanovkaNETS(SYS,f,name){
	S={0};
	while(S.size()){
		W={};
		for(i=0;i<S.size();++i){
			nets=SYS->G.getNET(S[i],0,"",1,#);
			if(!nets.size())continue;
			SS={};
			for(j=0;j<nets.size();++j)SS.push(&SYS->m[nets[j][0]]);
			Q=f.run(&SYS->m[S[i]],SS);
			for(j=0;j<Q.size();++j){
				p=nets[Q[j]][0];
				nets2=SYS->G.getNET(S[i],0,name,1,p);
				if(nets2.size())continue;
				SYS->G.NET(S[i],0,name,1,p);
				W.push(p);
				}
			}
		S=(vector)(set)W;
		}
}


var ComputeSpaceWAYS(SYS,name){
	table=(map)0;
	meway={};
	n=SubComputeSpaceWAYS(&SYS->G,0,name,&table,&meway);
	return n;
}

var SubComputeSpaceWAYS(G,n,name,table,meway){
	if(meway->indexOf(n)>=0)return 0;
	if(table->isset(n))return (*table)[n];
	nets=G->getMARKER(n,0,"",0,"END");
	if(nets.length())return 0;
	nets=G->getNET(n,0,name,1,#);
	if(!nets.size()){
		(*table)[n]=1;
		return 1;
		}
	meway->push(n);
	s=0;
	for(i=0;i<nets.size();++i)s+=SubComputeSpaceWAYS(G,nets[i][0],name,table,meway);
	if(s)(*table)[n]=s;
	meway->pop();
	return s;
}


void ComputeAllWAYS(SYS,name){
	SYS->WAYS={};
	S={0};
	SubComputeAllWAYS(SYS,S,name);
}

void SubComputeAllWAYS(SYS,S,name){
	nets=SYS->G.getNET(S[S.size()-1],0,name,1,#);
	if(!nets.size()){
		SYS->WAYS.push(S);
		return;
		}
	for(i=0;i<nets.size();++i)SubComputeAllWAYS(SYS,S+{nets[i][0]},name);
}




void PrintSolutesCompact(SYS){
	razdel="";
	for(i=0;i<80;++i)razdel+="=";
	for(i=0;i<SYS->WAYS.size();++i){
		row={};
		first=1;
		for(t=1;t<SYS->WAYS[i].size();++t){
			acces=&SYS->m[SYS->WAYS[i][t]];
			if(isset(SYS->functions.correctir)){
				if(first){
					first=0;
					PREV=*acces;
					}else{
					SYS->functions.correctir.run(&PREV,*acces);
					acces=&PREV;
					}
				}
			if(isset(SYS->functions.toString))
				str=SYS->functions.toString.run(acces);
				else str=getAuthorForm(acces);
			row.push(str);
			}
		Q=getzvit(row);
		trace(Q);
		tracex(razdel);
		echo(Q);
		echo(razdel+"\n");
		}
}



void UnloadSystem(SYS,reservcopy){
	if(!isset(SYS->namemodele))return;
	Q=getThisFileName().split("\\");
	Q[Q.size()-1]="Buffer";
	str=SYS->namemodele;
	if(isset(SYS->ver))str+=SYS->ver;
	if(isset(reservcopy))str+="_"+reservcopy;
	Q.push(str);
	Q=Q.implode("\\");
	str="G=(graf)0;\n";
	str+=SYS->G.export("G");
	str+="return G;";
	f=(function)0;
	f.setName("getbuffergraf");
	f.import(PROGRAM(str));
	f.integrate(Q);
	//---------------------------------------------------------------
	str="X={};";
	for(i=0;i<SYS->m.size();++i){
		str+="X.push("+getAuthorForm(&SYS->m[i])+");";
		}
	str+="return X;";
	f=(function)0;
	f.setName("getbufferunits");
	f.import(PROGRAM(str));
	f.integrate(Q);
	//---------------------------------------------------------------
	str="M=(map)0;";
	if(isset(SYS->filename)){
		s=SYS->filename;
		SYS->predoxranitelfilename=s.substr(WAY.length()+1);
		}
	tosave={"k","good","timezatratil","predoxranitelfilename"};
	for(i=0;i<tosave.size();++i)if(SYS->isset(tosave[i])){
		str+="M["+tosave[i].export()+"]="+getAuthorForm(&(*SYS)[tosave[i]])+";";
		}
	str+="return M;";
	f=(function)0;
	f.setName("getbufferparams");
	f.import(PROGRAM(str));
	f.integrate(Q);
	//---------------------------------------------------------------
	uninclude(Q+".txt");
	//if(!isset(reservcopy))UnloadSystem(SYS,(rand()%10)+1);
}


void LoadSystem(SYS){
	Q=getThisFileName().split("\\");
	Q[Q.size()-1]="Buffer";
	Q.push(SYS->namemodele+SYS->ver);
	Q=Q.implode("\\");
	f=getFunction("getbuffergraf",Q);
	SYS->G=f.run();
	f=getFunction("getbufferunits",Q);
	SYS->m=f.run();
	f=getFunction("getbufferparams",Q);
	M=f.run();
	keys=M.getKeys();
	for(i=0;i<keys.size();++i){
		(*SYS)[keys[i]]=M[keys[i]];
		}
}
