BeginPackage["loopTool`"];

dd::usage="";
vecD::usage="";
autoReduceVar::usage="";
stopAutoReduce::usage="";
nestedwhile::usage="";

coefficientList2::usage="";
intervalSign::usage="";

gatherBy::usage="";

tHold::usage="";
tHoldQ::usage="";
tApply::usage="";
tMapEvaluateAt::usage="";
		
tHoldOn::usage="";
tHoldOff::usage="";
tHoldStatus::usage="";
tHoldBlock::usage="";

solveAlways2::usage="";

bSum::usage="";
pSum::usage="";
bProduct::usage="";
pProduct::usage="";

projω::usage="";
projχ::usage="";
projExpand::usage="";
projSimplify::usage="";

zeroRegionPlot::usage="";

pSwitch::usage="";
ifMatchQ::usage="";

newvar::usage="";
newvarList::usage="";

Begin["`private`"];

Unprotect["loopTool`*"];
Unprotect["loopTool`private`*"];

Clear[vecD];
vecD[a_,Subscript[b_, c:(_Symbol|_Integer)]]:=
Module[{res,tmp,μ,d,n=0,int},
res/;Catch[
tmp=a//.((f_)^(j_Integer)):>(f^(int[j]));
tmp=tmp//.{
Dot[x_,y_]:>With[{u=n++},Subscript[x,μ[u]]Superscript[y,μ[u]]],
(((t_. b+x_.))^(int[2])):>With[{u=n++},Subscript[t b+x,μ[u]]Superscript[t b+x,μ[u]]]
};
If[!FreeQ[tmp/.(h:Subscript|Superscript)[x_,y_]:>h[x/.b->d,y],b],Throw[False]];
If[c[[0]]===Symbol&&!FreeQ[tmp/.(h:Subscript|Superscript)[x_,y_]:>h[x,y/.c->d],c],Throw[False]];
tmp=D[tmp,b]//Expand;
tmp=tmp//.{
Derivative[1,0][Subscript][t_. b+_.,c]/;c[[0]]===Symbol:>"dim"[c],
Derivative[1,0][Subscript][t_. b+_.,x_]:>KroneckerDelta[x,c],
Derivative[1,0][Superscript][t_. b+_.,x_]:>"invmetric"[x,c],
KroneckerDelta[x_,y_]Superscript[z_,y_]:>Superscript[z,x],
"invmetric"[x_,y_]Subscript[z_,y_]:>Superscript[z,x],
"invmetric"[y_,x_]Subscript[z_,y_]:>Superscript[z,x]
};
tmp=tmp//.{
"invmetric"[x__]:>"invmetric"@@Sort[{x}],
Superscript[x_,y_]Subscript[z_,y_]:>Dot@@Sort[{x,z}]
};
If[!FreeQ[tmp,μ],Throw[False]];
res=tmp/.int->Identity;
True
]
];

vecD[a_,Superscript[b_,c:(_Symbol|_Integer)]]:=
Module[{res,tmp},
res/;Catch[
tmp=a/.{Superscript->Subscript,Subscript->Superscript};
tmp=vecD[tmp,Subscript[b,c]];
If[tmp[[0]]===vecD,Throw[False]];
res=tmp/.{Superscript->Subscript,Subscript->Superscript,"invmetric"->"metric"};
True
]
];

(*dd[a_,Subscript[b_, c_]]:=
	Module[{tmp},
		tmp=Hold[a]//.{
			Subscript[x_, i_]Superscript[y_,i_]:>Dot[x,y],
			(t_. b+x_.)^2:>Dot[t b+x,t b+x]
		};
		tmp=ReleaseHold[tmp];
		tmp=D[tmp,b];
		tmp=tmp//. {
			Derivative[1,0][Subscript][t_. b+_.,c]->"dim",
			Dot[x_,t_?NumberQ]:>t Superscript[x,c],
			Dot[t_?NumberQ,x_]:>t Superscript[x,c],
			Subscript[p_, c]Derivative[1,0][Subscript][b,x_]:>Subscript[p, x]/;!x===c,
			Subscript[p_, c]Derivative[1,0][Superscript][b,x_]:>Superscript[p,x]/;!x===c,
			Derivative[1,0][Superscript][t_. b+_.,x_]:>KroneckerDelta[x,c],
			Derivative[1,0][Superscript][t_. b+_.,x_]:>"invmetric"[x,c]
		};
		tmp//.{
			"invmetric"[x_,y_](s_+t_):>"invmetric"[x,y]s+"invmetric"[x,y]t,
			"invmetric"[x_,y_] Subscript[z_, x_]:>Superscript[z,y],
			"invmetric"[x_,y_] Subscript[z_, y_]:>Superscript[z,x],
			KroneckerDelta[x_,y_](s_+t_):>KroneckerDelta[s,y]s+KroneckerDelta[x,y]t,
			KroneckerDelta[x_,y_]Superscript[z_,x_]:>Superscript[z,y],
			KroneckerDelta[x_,y_]Superscript[z_,y_]:>Superscript[z,x]
		}
];

dd[a_,Superscript[b_,c_]]:=
	Module[{tmp},
		tmp=Hold[a]/.{Superscript->Subscript,Subscript->Superscript};
		dd[ReleaseHold[tmp],Subscript[b, c]]/.
			{Superscript->Subscript,Subscript->Superscript,"invmetric"->"metric"}
	];

SetAttributes[dd,HoldAll];*)

autoReduceVar[var_,func_]:=(
	ToExpression["$autoReducted"<>ToString[var]<>"[_]=False;"];
	ToExpression[
		ToString[var]<>"[autoReduceVar__]:=Module[{tmp},
				("<>ToString[var]<>"[autoReduceVar]=Collect[tmp,"<>ToString[var]<>"[__],Together])/;(
					If[$autoReducted"<>ToString[var]<>"[autoReduceVar],Return[False]];
					If[MemberQ[Cases[{autoReduceVar},l_[___]:>l,Infinity],
									Pattern|PatternSequence|Blank|BlankSequence|
									BlankNullSequence|Optional|Repeated|RepeatedNull
							],
						Return[False];
					];
					Block[{"<>ToString[var]<>"},
						tmp="<>ToString[func]<>"["<>ToString[var]<>"[autoReduceVar]];
						If[MemberQ[tmp,"<>ToString[var]<>"[autoReduceVar],{0,Infinity}],
							tmp="<>ToString[var]<>"[autoReduceVar];
							$autoReducted"<>ToString[var]<>"[autoReduceVar]=True;
							False
							,True
						]
					]
				)
			];"
		];
);

stopAutoReduce[var_]:=(var[a__]=.;ToExpression["Remove[$autoReducted"<>ToString[var]<>"]"]);

nestedwhile[f_,len_]:=
	Module[{counter,pos,res},
		counter=ConstantArray[0,len];
		pos=len;
		While[True,
			res=f[counter];
			If[!res,
				If[pos==1,Break[]];
				counter[[pos;;]]=0;
				pos--,
				pos=len;
			];
			counter[[pos]]++;
		];
	];

coefficientList2[poly_,form_]:=
	Module[{f,res,allVar,var,diff,ratio},
		f=Catch[
			allVar=Variables[form];
			var=Select[allVar,PolynomialQ[form,#]&&Exponent[form,#]==1&,1];
			If[var==={},Throw[False],var=var[[1]]];
			ratio=Coefficient[form,var];
			diff=form/ratio-var//Expand;
			res=CoefficientList[poly /.var->var-diff,var];
			res=res/Table[ratio^i,{i,0,Length[res]-1}];
			True
			];
		Cancel[res]/;f
	];

coefficientList2[poly_,{form_}]/;form[[0]]=!=List:=coefficientList2[poly,form];

coefficientList2[poly_,{x_,y__}]:=coefficientList2[#,{y}]&/@coefficientList2[poly,x]//PadRight;

intervalSign[in_Interval]:=
	Module[{min,max},
		{min,max}={Min[in],Max[in]};
		Which[
			!FreeQ[{min,max},Min|Max],Indeterminate,
			min==max==0,0,
			min>0,Positive,
			max<0,Negative,
			min==0,NonNegative,
			max==0,NonPositive,
			True,Indeterminate
		]
	];

gatherBy[list_,f_/;f[[0]]=!=List]:=
	Gather[list,f[#1]===f[#2]&];

gatherBy[list_,f:{__}]:=
	Fold[gatherBy,list,f];

gatherBy[list_,{}]:=Gather[list];

gatherBy[list_]:=Gather[list];

Attributes[tHold]={HoldAll};

ssymb=Hold/@{
	Set,SetDelayed,UpSet,UpSetDelayed,TagSet,TagSetDelayed,TagUnset,
	Rule,RuleDelayed,ReleaseHold,Hold,HoldPattern,HoldComplete,
	tHold,tApply,tMapEvaluateAt,tHoldQ,If
};

gsymb=Union[
	Hold/@{
		Span,All,List,DirectedInfinity,
		Blank,BlankSequence,BlankNullSequence,Alternatives,Repeated,RepeatedNull,
		Pattern,Except,Longest,Shortest,OptionsPattern,PatternSequence,Verbatim,
		Condition,PatternTest,Optional,Default,
		Symbol,Integer,Real,Rational,Complex,Integers,Reals,Rationals,Complexes,
		Equal,Unequal,SameQ,UnsameQ,Less,Greater,LessEqual,GreaterEqual,Inequality,
		True,False,Function,Slot,SlotSequence
	}
];

tHoldOn//Clear;
Options[tHoldOn]={NumericFunction->True,NumericQ->True};

tHoldOn[OptionsPattern[]]:=(
	tHoldOff[];
	Unprotect[tHold,Part];
	$thStatus={
		NumericFunction->TrueQ[OptionValue[NumericFunction]],
		NumericQ->TrueQ[OptionValue[NumericQ]]
	};
	$thCheck=
		If[$thStatus[[1,2]],
			If[$thStatus[[2,2]],
				AtomQ[Unevaluated[#]]&&!NumericQ[Unevaluated[#]]&&
					FreeQ[Attributes[#],NumericFunction]&&#=!=Indeterminate&,
				AtomQ[Unevaluated[#]]&&!NumberQ[Unevaluated[#]]&&
					FreeQ[Attributes[#],NumericFunction]&&#=!=Indeterminate&
			],
			If[$thStatus[[2,2]],
				AtomQ[Unevaluated[#]]&&!NumericQ[Unevaluated[#]]&,
				AtomQ[Unevaluated[#]]&&!NumberQ[Unevaluated[#]]&
			]
		];
	tHold/:h_[x___,tHold[y___],z___]/;FreeQ[ssymb,Hold[h],{1},Heads->False]:=
		Module[{m,originalSymbol,temporarySymbol,holdRule,releaseHoldRule,result},
			originalSymbol=Complement[
				Cases[Hold[h,x,y,z]/.tHold->Hold,a_/;$thCheck[Unevaluated[a]]:>Hold[a],
					{0,∞},Heads->True],
				gsymb
			];
			temporarySymbol=Table[Unique["xxx"],{Length[originalSymbol]}];
			(*SetAttributes[Evaluate[temporarySymbol],Temporary];*)
			holdRule=Thread[originalSymbol->temporarySymbol]/.Hold->HoldPattern;
			releaseHoldRule=Thread[temporarySymbol:>Evaluate[originalSymbol]]/.Hold[a_]:>a;
			result=Hold[Evaluate[h@@(Hold[x,y,z]/.holdRule)]]/.releaseHoldRule;
			Remove/@temporarySymbol;
			tHold@@result
		];
	tHold[a___]/;!FreeQ[Hold[a],tHold]:=tHold@@(Hold[a]/.tHold[x___]:>x);
	Part/:Set[Part[a_,b___],c_]/;tHoldQ[a]:=
		If[tHoldQ[c],
			Block[{tHold=Unevaluated},Set@@Hold[Part[a,1,b],Evaluate[c]]],
			Block[{tHoldQ=False&},Set[Part[a,1,b],Unevaluated[c]]]
		];
	ReleaseHold[tHold[a___]]^:=a;
	Protect[tHold,Part];
);

tHoldOff[]:=(
	Unprotect[tHold,Part];
	$thStatus={};
	Clear[tHold];
	Quiet[Part/:Set[Part[a_,b___],c_]/;tHoldQ[a]=.];
	Protect[tHold,Part];
);

tHoldQ[a_]:=Module[{s},Block[{tHold=s},Head[a]]===s];

tHoldStatus[]:=$thStatus;

tApply[f_,a:HoldPattern[tHold[___]..]]:=Sequence@@(f/@{a});

(*tMapEvaluateAt[a_tHold,n_]:=
	Module[{c,f,res},
		(* メッセージ symbol::tag が On から Off に変更された場合、Update[symbol]を
			行わない限り、関数内で用いられる symbol::tag に変更が反映されない *)
		Update[MapAt];
		c=MapAt::partw=!=$Off[];
		If[c,
			f=Check[
				res=a[[0]]@@MapAt[Evaluate,ReleaseHold[Hold@@a],n];
				True,
				False,
				{MapAt::partw}
			],
			On[MapAt::partw];
			f=Quiet[				
				Check[
					res=a[[0]]@@MapAt[Evaluate,ReleaseHold[Hold@@a],n];
					True,
					False,
					{MapAt::partw}
				],
				{MapAt::partw}
			];
			Off[MapAt::partw];
		];
		res/;f
	];*)

Attributes[tHoldBlock]=HoldFirst;

tHoldBlock[in_,opt:OptionsPattern[]]:=
	Module[{st,res},
		st=tHoldStatus[];
		tHoldOn[opt];
		res=in;
		If[st==={},
			tHoldOff[],
			tHoldOn[st]
		];
		res
	];		

tHoldOff[];

(*
tHold2[Span]=Span;
tHold2[All]=All;
tHold2[List]=List;
*)

(*tHold[a_Integer]:=a;
tHold[a_Rational]:=a;
tHold[a_Real]:=a;
tHold[a_Complex]:=a;
tHold[a_]/;Length[{a}]==1&&AtomQ[a]&&Hold[a]===Hold[Evaluate[a]]:=a;
*)

(*
tHold/:h_[x___,y:tHold[___],z___]/;FreeQ[ssymb,Hold[h],{1},Heads->False]:=
		tHold@@(
			Hold[
				Evaluate[
					h@@(Hold[x,y,z]/.tHold[a___]:>a/.
						a_Symbol/;FreeQ[ssymb,Hold[a],{1},Heads->False]:>tHold2[a])
				]
			]//.
			tHold2[a___]:>a
		);
*)

(*
tApply[f_,a:HoldPattern[tHold[___]..]]:=
	tHold@@Block[{tHold=Hold},
		f@@@Hold[a]
	];
*)

parallelCollect[expr_,var_,h_]:=
	Module[{i=1,f,res1,tmp},
		tmp=Reap[res1=Collect[expr,var,(Sow[#];f[i++])&];];
		tmp=If[tmp[[2]]=!={},tmp[[2,1]],{}];
		DistributeDefinitions[tmp];
		tmp=ParallelTable[h[tmp[[i]]],{i,Length[tmp]}];
		ParallelEvaluate[Remove[tmp,i]];
		tmp=Thread[Array[f,Length[tmp]]->tmp];
		res1/.Dispatch[tmp]
	];

solveAlways2[a_,b_,c___]:=
	Module[{tmp,tmp2,tmp3,i,c1,v},
		tmp=Solve[!Eliminate[!a,b],c];
		Select[tmp,Simplify[a/.#]&]
	];

Attributes[bSum]={HoldFirst};

bSum[a_,b___,{i_,x1_,x2_},c___]:=
	Module[{s=Simplify[Sign[x2-x1]],sum},
		(	
			Distribute[
				sum[
					Switch[
						s,
						_?NonNegative,Sum[sum[a,c],{i,Expand[x1+1],Expand[x2]}],
						_?Negative,-Sum[sum[a,c],{i,Expand[x2+1],Expand[x1]}]
					],
					b
				]
			]/.sum[h_. sum[x_,y___],z___]:>sum[h x,z,y]/.sum->bSum
		)/;IntegerQ[s]
	];

bSum[a_,b___,{i_,x1_,x2_},c___]/;FreeQ[a,i]:=bSum[a(x2-x1),b,c];
		
bSum[a_]:=a;

Attributes[pSum]={HoldFirst};

pSum[a_,b___,{i_,x1_,x2_},c___]:=
	Module[{s=Simplify[Sign[x2-x1]],sum},
		(	
			Distribute[
				sum[
					Switch[
						s,
						_?NonNegative,Sum[sum[a,c],{i,Expand[x1],Expand[x2]}],
						_?Negative,-Sum[sum[a,c],{i,Expand[x2+1],Expand[x1-1]}]
					],
					b
				]
			]/.sum[h_. sum[x_,y___],z___]:>sum[h x,z,y]/.sum->pSum
		)/;IntegerQ[s]
	];

pSum[a_]:=a;

pSum[0,___]=0;

Attributes[bProduct]={HoldFirst};

bProduct[a_,b___,{i_,x1_,x2_},c___]:=
	Module[{s=Simplify[Sign[x2-x1]],prod},
		(	
			Distribute[
				prod[
					Switch[
						s,
						_?NonNegative,Product[prod[a,c],{i,Expand[x1+1],Expand[x2]}],
						_?Negative,1/Product[prod[a,c],{i,Expand[x2+1],Expand[x1]}]
					],
					b
				]
			]/.prod[prod[x_,y___]^h_.,z___]:>prod[x^h,z,y]/.prod->bProduct
		)/;IntegerQ[s]
	];

bProduct[a_,b___,{i_,x1_,x2_},c___]/;FreeQ[a,i]:=bProduct[a,b,c]^(x2-x1);

bProduct[a_]:=a;

Attributes[pProduct]={HoldFirst};

pProduct[a_,b___,{i_,x1_,x2_},c___]:=
	Module[{s=Simplify[Sign[x2-x1]],prod},
		(	
			Distribute[
				prod[
					Switch[
						s,
						_?NonNegative,Product[prod[a,c],{i,Expand[x1],Expand[x2]}],
						_?Negative,1/Product[prod[a,c],{i,Expand[x2+1],Expand[x1-1]}]
					],
					b
				]
			]/.prod[prod[x_,y___]^h_.,z___]:>prod[x^h,z,y]/.prod->pProduct
		)/;IntegerQ[s]
	];

pProduct[a_]:=a;

pProduct[1,___]=1;

zeroRegionPlot[f_,{a_,a0_,a1_},{b_,b0_,b1_},p_:20,d_:10^-10,opt___]:=
	RegionPlot[
		Chop[
			SetPrecision[f,p]/.
				{a->SetPrecision[ai,p],b->SetPrecision[bi,p]},
		d]==0,
		{ai,a0,a1},{bi,b0,b1},opt
	];

Clear[projω];

projω[a_Integer,b_Integer,c_][d_Integer]:=If[Mod[d-b,a]==0,c^d,0];
projω[a_Integer,b_Integer,c_][d_+e_Integer]:=c^e projω[a,b-e,c][d];

projω[a_Integer,b_Integer,c_]:=projω[-a,b,c]/;Negative[a];
projω[a_Integer,b_Integer,c_]:=With[{k=Mod[b,a]},projω[a,k,c]/;k!=b];

projω/:projω[a_Integer,b_Integer,_]projω[a_Integer,e_Integer,_]/;Mod[b-e,a]!=0:=0;
projω/:projω[a_Integer,b_Integer,c_]projω[a_Integer,b_Integer,e_]:=projω[a,b,c e];
projω/:projω[a_Integer,b_Integer,c_]^e_Integer?Positive:=projω[a,b,c^e];
projω/:projω[a_Integer,b_Integer,c_]projω[e_Integer,f_Integer,g_]/;a!=e:=
	Module[{k=LCM[a,e],i},
		Expand[Sum[projω[k,b+i a,c],{i,0,k/a-1}]Sum[projω[k,f+i e,g],{i,0,k/e-1}]]
	];

projω/:projω[a_Integer,b_Integer,c_][p_. d_]projω[e_Integer,f_Integer,g_][q_. d_]/;IntegerQ[p]&&IntegerQ[q]:=
	With[{k=LCM[p,q]},
		projω[a k/p,b k/p,c^(p/k)]projω[e k/q,f k/q,g^(q/k)]/.x_projω:>x[k d]
	];

projω/:projω[a_Integer,b_Integer,c_][d_]^e_Integer?Positive:=projω[a,b,c]^e/.x_projω:>x[d];

projExpand[in_]:=Module[{i},in/.(projω|projχ)[a_,b_,c_][k_]:>((c^k)/a) Sum[(((-1))^((2 i (b-k))/a)),{i,a}]];

projSimplify[in_]:=
	FixedPoint[
		Expand[#/.
			projω[a_Integer,b_Integer,c_][p_. d_+e_]/;IntegerQ[p]&&FreeQ[d,e]:>pe[projχ[a,b,c][p d+e],d]/.
			projω[a_Integer,b_Integer,c_][d_Integer e_]:>
				Module[{k},
					k=GCD[a,b,d];
					Which[
						k!=1,projω[(a/k),(b/k),(c^k)][((d e)/k)],
						!CoprimeQ[a,d],0,
						True,k=mm[a,b,d];projω[a,k,(c^d)][e]
					]
				]
		]&,
		in
	];

mm[a_,b0_,c0_]:=
	Module[{b,c},
		{b,c}={b0,c0};
		While[True,
			If[Divisible[b,c],Return[Mod[b/c,a]]];
			b+=a
		]
	];

pe[in_,s_]:=
	Module[{tmp,lcm,fac,F},
		tmp=Cases[in,x_projχ[t_]/;!FreeQ[t,s]:>Coefficient[t,s]x[[1]],{0,∞}];
		lcm=LCM@@tmp;
		tmp=Sum[in F[s],{s,0,2lcm-1}]/.projχ->projω;
		If[tmp===0,Return[0]];
		fac=Quiet[Divide@@Partition[Coefficient[tmp,Array[F,2lcm,0]],lcm]];
		fac=DeleteCases[fac,Indeterminate]//Union;
		If[!MatchQ[fac,{_}],Abort[]];
		fac=(1/fac[[1]])^(1/lcm)//PowerExpand;
		tmp/.F[a_]/;a>=lcm->0/.F[a_]:>projω[lcm,0,fac][s-a]
	];

(*Clear[projω];
projω[a_Integer,b_Integer,c_][d_Integer]:=If[Mod[d-b,a]==0,c^d,0];
projω[a_Integer,b_Integer,c_]:=With[{k=Mod[b,a]},projω[a,k,c]/;k!=b];
projω[a_Integer,b_Integer,c_][d_+e_Integer]:=c^e projω[a,b-e,c][d];
projω/:projω[a_Integer,b_Integer,_]projω[a_Integer,e_Integer,_]/;Mod[b-e,a]!=0:=0;
projω/:projω[a_Integer,b_Integer,c_]projω[a_Integer,b_Integer,e_]:=projω[a,b,c e];
projω/:projω[a_Integer,b_Integer,c_]^e_Integer?Positive:=projω[a,b,c^e];
projω/:projω[a_Integer,b_Integer,c_]projω[e_Integer,f_Integer,g_]/;a!=e:=
	With[{k=LCM[a,e]},
		Expand[Sum[projω[k,b+i a,c],{i,0,k/a-1}]Sum[projω[k,f+i e,g],{i,0,k/e-1}]]
	];
projω/:projω[a_,b_,c_][p_. d_]projω[e_,f_,g_][q_. d_]:=
	With[{k=LCM[p,q]},projω[a k/p,b k/p,c^(p/k)]projω[e k/q,f k/q,g^(q/k)]/.x_projω:>x[k d]];
projω/:projω[a_,b_,c_][d_]^e_Integer?Positive:=projω[a,b,c]^e/.x_projω:>x[d];

projExpand[in_]:=Module[{i},in/.(projω|projχ)[a_,b_,c_][k_]:>c^k/a Sum[(-1)^(-2i b/a) ((-1)^(2i/a))^k,{i,a}]];
*)

pSwitch[expr_,fv:(_Rule|_RuleDelayed)...]:=
	Module[{res,tmp,rul},
		Do[
			tmp=Cases[expr,rul,{0}];
			If[tmp=!={},res=tmp[[1]];Break[]],
			{rul,{fv}}
		];
		res/;ValueQ[res]
	];

(*Attributes[ifMatchQ]={HoldRest};
ifMatchQ[expr_,form_,t_,f_:Null]:=pSwitch[expr,form:>t,_:>f];*)

newvar[a_]:=
Module[{vl},
vl={\[FormalA],\[FormalB],\[FormalC],\[FormalD],\[FormalE],\[FormalF],\[FormalG],\[FormalH],\[FormalI],\[FormalJ],\[FormalK],\[FormalL],\[FormalM],\[FormalN],\[FormalO],\[FormalP],\[FormalQ],\[FormalR],\[FormalS],\[FormalT],\[FormalU],\[FormalV],\[FormalW],\[FormalZ],\[FormalY],\[FormalZ],\[FormalCapitalA],\[FormalCapitalB],\[FormalCapitalC],\[FormalCapitalD],\[FormalCapitalE],\[FormalCapitalF],\[FormalCapitalG],\[FormalCapitalH],\[FormalCapitalI],\[FormalCapitalJ],\[FormalCapitalK],\[FormalCapitalL],\[FormalCapitalM],\[FormalCapitalN],\[FormalCapitalO],\[FormalCapitalP],\[FormalCapitalQ],\[FormalCapitalR],\[FormalCapitalS],\[FormalCapitalT],\[FormalCapitalU],\[FormalCapitalV],\[FormalCapitalW],\[FormalCapitalZ],\[FormalCapitalY],\[FormalCapitalZ]};
vl=Complement[vl,Cases[a,Alternatives@@vl,{0,∞}]];
If[vl==={},Unique["$formal"],vl[[1]]]
];

newvarList[a_,b_]:=Take[Flatten[Nest[{#,newvar[#]}&,{a},b]],-b];

Protect["loopTool`*"];
Protect["loopTool`private`*"];
Unprotect["loopTool`$*"];
Unprotect["loopTool`private`$*"];

End[];

EndPackage[];