diff --git a/current_generator/helspin.frm b/current_generator/helspin.frm
new file mode 100644
index 0000000..99caaf5
--- /dev/null
+++ b/current_generator/helspin.frm
@@ -0,0 +1,134 @@
+*/**
+*  \brief Procedures for dealing with helicity spinors
+*
+*  \authors   The HEJ collaboration (see AUTHORS for details)
+*  \date      2019
+*  \copyright GPLv2 or later
+*/
+on shortstats;
+cf Conjugate,Current;
+#define CHAINS "AngleChain,SquareChain,SpinorChain"
+ctensor `CHAINS';
+
+* internal symbols, rename?
+v p,q,k,l;
+cf dum;
+ctensor ct;
+s x,y;
+i mu1,...,mu50;
+
+#procedure InsCurrent
+
+   id Current(+1, ?a) = Current(-1, reverse_(?a));
+*  hack
+*  with ?a as pattern FORM has problems if the arguments are sums of momenta
+   #do N=3,50
+      id Current(-1, mu1?,...,mu`N'?) = SpinorChain(mu1,...,mu`N');
+   #enddo
+
+#endprocedure
+
+#procedure SortArgs
+
+   #do F={AngleChain,SquareChain}
+      antisymmetrize `F':2;
+   #enddo
+
+#endprocedure
+
+#procedure DoConjugate
+
+   splitarg Conjugate;
+   repeat id Conjugate(x?, y?, ?a) = Conjugate(x) + Conjugate(y, ?a);
+   normalize Conjugate;
+   id Conjugate(AngleChain(p?, q?)) = -SquareChain(p, q);
+   id Conjugate(SquareChain(p?, q?)) = -AngleChain(p, q);
+   id Conjugate(SpinorChain(?a)) = dum(reverse_(?a));
+   id dum(?a) = SpinorChain(?a);
+
+#endprocedure
+
+#procedure Fierz(MU)
+
+   once SpinorChain(p?, `MU', q?)*SpinorChain(k?, `MU', l?) = (
+      2*AngleChain(p, k)*SquareChain(l, q)
+   );
+
+#endprocedure
+
+#procedure MomentumToSpinorsInSpinorChain(P)
+
+   id SpinorChain(p?, ?a, `P', ?b, q?) = dum(
+      mod_(nargs_(p, ?a),2), mod_(nargs_(?b, q),2),
+      SpinorChain(p, ?a, `P', ?b, q)
+   );
+   id dum(1, 1, SpinorChain(p?, ?a, `P', ?b, q?)) = (
+      AngleChain(p, ?a, `P')*SquareChain(`P', ?b, q)
+   );
+   id dum(0, 0, SpinorChain(p?, ?a, `P', ?b, q?)) = (
+      SpinorChain(p, ?a, `P')*SpinorChain(`P', ?b, q)
+   );
+   if(count(dum,1)>0);
+      print "even number of arguments in spinor chain in %t";
+      exit;
+   endif;
+
+#endprocedure
+
+#procedure MomentumToSpinorsInAngleChain(P)
+
+   id AngleChain(p?, ?a, `P', ?b, q?) = dum(
+      mod_(nargs_(p, ?a),2), mod_(nargs_(?b, q),2),
+      AngleChain(p, ?a, `P', ?b, q)
+   );
+   id dum(1, 0, AngleChain(p?, ?a, `P', ?b, q?)) = (
+      AngleChain(p, ?a, `P')*Conjugate(SpinorChain(`P', ?b, q))
+   );
+   id dum(0, 1, AngleChain(p?, ?a, `P', ?b, q?)) = (
+      SpinorChain(p, ?a, `P')*AngleChain(`P', ?b, q)
+   );
+   if(count(dum,1)>0);
+      print "odd number of arguments in angle chain in %t";
+      exit;
+   endif;
+
+#endprocedure
+
+#procedure MomentumToSpinorsInSquareChain(P)
+
+   id SquareChain(p?, ?a, `P', ?b, q?) = dum(
+      mod_(nargs_(p, ?a),2), mod_(nargs_(?b, q),2),
+      SquareChain(p, ?a, `P', ?b, q)
+   );
+   id dum(1, 0, SquareChain(p?, ?a, `P', ?b, q?)) = (
+      SquareChain(p, ?a, `P')*SpinorChain(`P', ?b, q)
+   );
+   id dum(0, 1, SquareChain(p?, ?a, `P', ?b, q?)) = (
+      Conjugate(SpinorChain(p, ?a, `P'))*SquareChain(`P', ?b, q)
+   );
+   if(count(dum,1)>0);
+      print "odd number of arguments in angle chain in %t";
+      exit;
+   endif;
+
+#endprocedure
+
+
+#procedure MomentumToSpinors(P)
+
+   repeat;
+      #do CHAIN={`CHAINS'}
+         id `CHAIN'(?a, `P', `P', ?b) = 0;
+         #call MomentumToSpinorsIn`CHAIN'(`P')
+      #enddo
+   endrepeat;
+
+#endprocedure
+
+#procedure ToSpinors(?PS)
+
+   #do P={`?PS'}
+      #call MomentumToSpinors(`P')
+   #enddo
+
+#endprocedure
diff --git a/current_generator/jW_uno.frm b/current_generator/jW_uno.frm
new file mode 100644
index 0000000..9e8fb50
--- /dev/null
+++ b/current_generator/jW_uno.frm
@@ -0,0 +1,71 @@
+*/**
+*  \brief Calculation of W unordered current
+*
+*  \authors   The HEJ collaboration (see AUTHORS for details)
+*  \date      2019
+*  \copyright GPLv2 or later
+*/
+#include- helspin.frm
+
+s h,s1g,s1W,s1gW,s2g,sbg,tag,taW,taW1,taWg;
+v p,p1,p2,pa,pb,pg,pl,plbar,pW,pr,q1,q1g;
+i mu,nu,rho,sigma;
+i mu1,...,mu20;
+cf epsW,epsg,j2b;
+
+#do h1={+,-}
+   #do h2={+,-}
+      #do hg={+,-}
+*        eq:U1tensor in developer manual
+         l [U1 `h1'`h2'`hg'] = epsW(-1, rho)*epsg(`hg'1, nu)*j2b(`h2'1, mu)*(
+            + Current(`h1'1, p1, nu, p1+pg, mu, pa-pW, rho, pa)/(s1g*taW)
+            + Current(`h1'1, p1, nu, p1+pg, rho, p1+pg+pW, mu, pa)/(s1g*s1gW)
+            + Current(`h1'1, p1, rho, p1+pW, nu, p1+pg+pW, mu, pa)/(s1W*s1gW)
+         );
+
+*        eq:U2tensor in developer manual
+         l [U2 `h1'`h2'`hg'] = epsW(-1, rho)*epsg(`hg'1, nu)*j2b(`h2'1, mu)*(
+            + Current(`h1'1, p1, mu, pa - pW - pg, nu, pa - pW, rho, pa)/(taW*taWg)
+            + Current(`h1'1, p1, mu, pa - pW - pg, rho, pa - pg, nu, pa)/(tag*taWg)
+            + Current(`h1'1, p1, rho, p1 + pW, mu, pa - pg, nu, pa)/(s1W*tag)
+         );
+
+*        eq:Ltensor in developer manual
+         l [L `h1'`h2'`hg'] = epsW(-1, rho)*epsg(`hg'1, nu)*j2b(`h2'1, mu)*(
+            Current(`h1'1, p1, sigma, pa - pW, rho, pa)/taW +
+            Current(`h1'1, p1, rho, p1 + pW, sigma, pa)/s1W
+         )*(
+            ((pb(nu)/sbg + p2(nu)/s2g)*q1g.q1g + 2*q1(nu) - pg(nu))*d_(mu, sigma)
+            - 2*pg(mu)*d_(nu, sigma)
+            + (2*pg(sigma) - q1(sigma))*d_(mu, nu)
+         )/taW1;
+      #enddo
+   #enddo
+#enddo
+
+* choice of best reference vector (p2 or pb)
+id epsg(h?, mu?)*j2b(h?, nu?) = epsg(h, mu, p2)*j2b(h, nu);
+also epsg(h?, mu?) = epsg(h, mu, pb);
+
+id epsW(h?, mu?) = Current(h, pl, mu, plbar);
+
+id epsg(-1, mu?, pr?) = sqrt_(2)/2*SpinorChain(pr, mu, pg)/AngleChain(pg,pr);
+id epsg(+1, mu?, pr?) = sqrt_(2)/2*SpinorChain(pg, mu, pr)/SquareChain(pg,pr);
+id j2b(h?, mu?) = Current(h, p2, mu, pb);
+
+#call InsCurrent;
+.sort
+multiply replace_(q1,pa-p1-pW);
+multiply replace_(pW,pl+plbar);
+.sort
+
+#call ToSpinors(p1,pa,pl,plbar,pg,p2,pb)
+
+#do MU={mu,nu,rho,sigma}
+   #call Fierz(`MU')
+#enddo
+#call SortArgs
+.sort
+
+print+s;
+.end