text:
/***************************************************************************//**
\file PJMCoords.h
\brief Contains class OmniCoords.
Code that converts between various different Heliocentric & Galctocentric
coordinate systems.

  PJMCoords.h (adapted from Coordinates.h)

  C++ code written by Paul McMillan 2010,
                      Walter Dehnen, 1995-96,
  Oxford University, Department of Physics, Theoretical Physics.
  address: 1 Keble Road, Oxford OX1 34P, United Kingdom
  e-mail:  p.mcmillan1@physics.ox.ac.uk

********************************************************************************

  GENERAL REMARKS

  There are six coordinate systems which can be used, three galactocentric,
  and three heliocentric. Usually, modellers use a galactocentric coordinate
  system, whereas the observer's natural coordinate systems are heliocentric
  and polar, the latter since position on the sky and distance are completely
  different observables. The so called equatorial coordinates (distance,
  right ascension, declination and their time derivatives) are orientad at
  the earth's polar axis. However, because of the earth's precession, that
  axis is not at a fixed angle with respect to very distant objects.
  Therefore, one often uses so-called galactic coordinates which are also
  heliocentric but orientated with respect to the galactic centre and the
  galactic poles, respectively. This coordinate system is changing as well
  with the time scale being the sun's orbital time (2x10^8 yr) much longer
  than the earth's precession time (10^4yr).

********************************************************************************

  PRECISE DEFINITION OF THE COORDINATE SYSTEMS

  GCA Galactocentric CArtesian
      position = (X,Y,Z),  velocity = (vX,vY,vZ)
      units: as defined in Units.h (kpc, kpc/Myr)
         These are inertial right-handed coordinates with e_X pointing in the
      present direction of the sun and e_Z towards the north galactic pole.

  GCY Galactocentric CYlindrical:
      position = (R,Z,phi),  velocity = (vR,vZ,vphi)
      units: as defined in Units.h (kpc, radian, kpc/Myr)
         The cylindrical galactocentric coordinates are easily defined in
      terms of the galactrocentric cartesian coordinates introduced above:
		X = R cos(phi), Y = R sin(phi), Z = z
       	vR = dR/dt, vz = dz/dt, vphi = R dphi/dt.

  LSR Local Standard of Rest
      position = (x,y,z), velocity = (u,v,w)
      units: as defined in Units.h (kpc, kpc/Myr)
         The local standard of rest (LSR) represents an inertial (non-rota-
      ting) coordinate system with origin of position on the sun, e_x poin-
      ting towards the Galactic centre (GC), e_y in direction of Galactic
      rotation (GR), and e_z towards NGP, i.e.
		(x,y,z) = (R0-X, -Y, Z-Zsun)
      where R0 is the distance sun-GC, and Zsun is the solar height above the
      plane. The LSR's origin of velocity is on that of a (hypothetic) star
      on a circular orbit at the solar position, i.e.
		(u,v,w) = (-v_X, v_circ-v_Y, v_Z)
      where v_circ is the circular rotation velocity at R=R0, for the Milky
      Way it is negative (it's adopted value and those for R0, Zsun are taken
      from the file Constants.h). The velocity (u,v,w) of a star w.r.t. LSR
      are often called its `peculiar motion'.
      In the literature the direction of the x or u vector is not unique,
      some authors use GC others GAC direction. Here, GC direction is used,
      in order to end up with a right-handed coordinate system.

  HCA HelioCentric Cartesian
      position = (x,y,z), velocity = (vx,vy,vz)
      units: as defined in Units.h (kpc, kpc/Myr)
         This coordinate system differs from the above (LSR) only in the
      origin of the velocity, which is the solar motion.
      A direct consequence is that transformations to the Polar coordinates
      does not involve the peculiar motion of the sun.

  HGP Heliocentric Galactic Polar:
      position = (r,l,b), velocity = (vr,ml,mb)
      units: as defined in Units.h (kpc,radian,kpc/Myr,radian/Myr)
	  These usually called `galactic coordinates' are often used for
      observations of galactic objects. They can be defined in terms of the
      HCA as follows
		x   = r * cos(b) * cos(l)   e_x points to GC
		y   = r * cos(b) * sin(l)
		z   = r * sin(b)
               vr  = dr/dt
               ml* = dl/dt * cos(b)
               mb  = db/dt
      l and b are usually called galactic longitude and galactic latitude,
      respectively. Note that the peculiar motion of the sun contributes to
      the radial velocity and proper motion of an object at rest in the
      local standard of rest

  HEQ Heliocentric Equatorial Polar:
      position = (r,a,d), velocity = (vr,ma*,md)
      units: as defined in Units.h (kpc,radian,kpc/Myr,radian/Myr)
      NOTE:  ma* = cos(d) * da/dt = cos(d) * ma
         The equatorial coordinates (distance, right ascension, declination)
      are those to be used in the telescopes. They are fixed to the earth
      polar axis, which changes rapidly enough to make these coordinates less
      useful than the other. Hence, most observers give galactic coordinates.
      The precise definition depends on epoch, by default J2000 is used, but
      B1950 is also possible, the epoch may be given as an argument.

  --------------
  @) GC, GAC, GR, GAR, and NGP denote Galactic centre, Galactic anticentre,
  Galactic rotation, Galactic antirotation, and north Galactic pole,
  respectively.

********************************************************************************

  Summary of Coordinate Systems:

   centre   |                coordinate system
   x   v    | cartesian |  cylindrical | spherical polar
  ----------+--------------------------------------------
  GC   GC @)|	 GCA	      GCY	        -
  sun  LSR  |   LSR           -                -
  sun  sun  |   HCA           -             HGP, HEQ

  The Transformations between systems with different centres is always done
  in the cartesian frames.

  --------------
  @) GC denotes the galactic centre

********************************************************************************
*                                                                              *
*  Parameter dependences of the basic transformations between the coordinate   *
*  systems:                                                                    *
*                                                                              *
*  GCA  <-->  GCY      -                                                       *
*  GCA  <-->  LSR      depends on R0, zsun, Vcirc(R0)                          *
*  LSR  <-->  HCA      depends on (U,V,W)sun                                   *
*  HCA  <-->  HGP      -                                                       *
*  HCA  <-->  HEQ      depends on epoch (default is J2000)                     *
*                                                                              *
*                                                                              *
*******************************************************************************

Paul's notes

Eventually I decided that I should probably use some proper c++ for this
(i.e. create a class that stores the transformation constants)

*/

#ifndef _Galactic_Coordinates_PJM_def_
#define _Galactic_Coordinates_PJM_def_ 1
#include "Constants.h"
#include "Vector.h"
#include "Matrix.h"

#ifndef _Galactic_Coordinates_def_
#define _Galactic_Coordinates_def_ 1
typedef Vector<double,6> GCA;
typedef Vector<double,6> GCY;
typedef Vector<double,6> LSR;
typedef Vector<double,6> HCA;
typedef Vector<double,6> HGP;
typedef Vector<double,6> HEQ;
#endif

typedef Vector<bool,6> bool6;
typedef Vector<double,6> vec6;
typedef Matrix<double,3,3> mat33;

/**
\brief Converts between various different Heliocentric & Galctocentric
coordinate systems.

  GENERAL REMARKS

  There are six coordinate systems which can be used, three galactocentric,
  and three heliocentric. Usually, modellers use a galactocentric coordinate
  system, whereas the observer's natural coordinate systems are heliocentric
  and polar, the latter since position on the sky and distance are completely
  different observables. The so called equatorial coordinates (distance,
  right ascension, declination and their time derivatives) are orientad at
  the earth's polar axis. However, because of the earth's precession, that
  axis is not at a fixed angle with respect to very distant objects.
  Therefore, one often uses so-called galactic coordinates which are also
  heliocentric but orientated with respect to the galactic centre and the
  galactic poles, respectively. This coordinate system is changing as well
  with the time scale being the sun's orbital time (2x10^8 yr) much longer
  than the earth's precession time (10^4yr).

********************************************************************************

  PRECISE DEFINITION OF THE COORDINATE SYSTEMS

  GCA Galactocentric CArtesian
      position = (X,Y,Z),  velocity = (vX,vY,vZ)
      units: as defined in Units.h (kpc, kpc/Myr)
         These are inertial right-handed coordinates with e_X pointing in the
      present direction of the sun and e_Z towards the north galactic pole.

  GCY Galactocentric CYlindrical:
      position = (R,Z,phi),  velocity = (vR,vZ,vphi)
      units: as defined in Units.h (kpc, radian, kpc/Myr)
         The cylindrical galactocentric coordinates are easily defined in
      terms of the galactrocentric cartesian coordinates introduced above:
		X = R cos(phi), Y = R sin(phi), Z = z
       	vR = dR/dt, vz = dz/dt, vphi = R dphi/dt.

  LSR Local Standard of Rest
      position = (x,y,z), velocity = (u,v,w)
      units: as defined in Units.h (kpc, kpc/Myr)
         The local standard of rest (LSR) represents an inertial (non-rota-
      ting) coordinate system with origin of position on the sun, e_x poin-
      ting towards the Galactic centre (GC), e_y in direction of Galactic
      rotation (GR), and e_z towards NGP, i.e.
		(x,y,z) = (R0-X, -Y, Z-Zsun)
      where R0 is the distance sun-GC, and Zsun is the solar height above the
      plane. The LSR's origin of velocity is on that of a (hypothetic) star
      on a circular orbit at the solar position, i.e.
		(u,v,w) = (-v_X, v_circ-v_Y, v_Z)
      where v_circ is the circular rotation velocity at R=R0, for the Milky
      Way it is negative (it's adopted value and those for R0, Zsun are taken
      from the file Constants.h). The velocity (u,v,w) of a star w.r.t. LSR
      are often called its `peculiar motion'.
      In the literature the direction of the x or u vector is not unique,
      some authors use GC others GAC direction. Here, GC direction is used,
      in order to end up with a right-handed coordinate system.

  HCA HelioCentric Cartesian
      position = (x,y,z), velocity = (vx,vy,vz)
      units: as defined in Units.h (kpc, kpc/Myr)
         This coordinate system differs from the above (LSR) only in the
      origin of the velocity, which is the solar motion.
      A direct consequence is that transformations to the Polar coordinates
      does not involve the peculiar motion of the sun.

  HGP Heliocentric Galactic Polar:
      position = (r,l,b), velocity = (vr,ml,mb)
      units: as defined in Units.h (kpc,radian,kpc/Myr,radian/Myr)
	  These usually called `galactic coordinates' are often used for
      observations of galactic objects. They can be defined in terms of the
      HCA as follows
		x   = r * cos(b) * cos(l)   e_x points to GC
		y   = r * cos(b) * sin(l)
		z   = r * sin(b)
               vr  = dr/dt
               ml* = dl/dt * cos(b)
               mb  = db/dt
      l and b are usually called galactic longitude and galactic latitude,
      respectively. Note that the peculiar motion of the sun contributes to
      the radial velocity and proper motion of an object at rest in the
      local standard of rest

  HEQ Heliocentric Equatorial Polar:
      position = (r,a,d), velocity = (vr,ma*,md)
      units: as defined in Units.h (kpc,radian,kpc/Myr,radian/Myr)
      NOTE:  ma* = cos(d) * da/dt = cos(d) * ma
         The equatorial coordinates (distance, right ascension, declination)
      are those to be used in the telescopes. They are fixed to the earth
      polar axis, which changes rapidly enough to make these coordinates less
      useful than the other. Hence, most observers give galactic coordinates.
      The precise definition depends on epoch, by default J2000 is used, but
      B1950 is also possible, the epoch may be given as an argument.

  --------------
  @) GC, GAC, GR, GAR, and NGP denote Galactic centre, Galactic anticentre,
  Galactic rotation, Galactic antirotation, and north Galactic pole,
  respectively.

********************************************************************************

  Summary of Coordinate Systems:

   centre   |                coordinate system
   x   v    | cartesian |  cylindrical | spherical polar
  ----------+--------------------------------------------
  GC   GC @)|	 GCA	      GCY	        -
  sun  LSR  |   LSR           -                -
  sun  sun  |   HCA           -             HGP, HEQ

  The Transformations between systems with different centres is always done
  in the cartesian frames.

  --------------
  @) GC denotes the galactic centre

********************************************************************************
*                                                                              *
*  Parameter dependences of the basic transformations between the coordinate   *
*  systems:                                                                    *
*                                                                              *
*  GCA  <-->  GCY      -                                                       *
*  GCA  <-->  LSR      depends on R0, zsun, Vcirc(R0)                          *
*  LSR  <-->  HCA      depends on (U,V,W)sun                                   *
*  HCA  <-->  HGP      -                                                       *
*  HCA  <-->  HEQ      depends on epoch (default is J2000)                     *
*                                                                              *
*                                                                              *
*******************************************************************************

*/

class OmniCoords {
  //bool knowHEQ,knowHGP,knowHCA,knowLSR,knowGCA,knowGCY;
  bool6 know;
  double Rsun,zsun,vcsun,Usun,Vsun,Wsun, epoch;
  mat33   EtoP;
  void SetTrans();
  void HEQfromHCA();  void HGPfromHCA();  void HCAfromLSR();
  void LSRfromGCA();  void GCAfromGCY();
  void Backward (int);
  void HCAfromHEQ();  void HCAfromHGP();  void LSRfromHCA();
  void GCAfromLSR();  void GCYfromGCA();
  void Forward(int);
  vec6 rv[6];
 public:
  void change_sol_pos(double,double);
  void change_vc(double);
  void change_vsol(double,double,double);
  void set_SBD10();
  void set_DB98();
  void change_epoch(double);

  void give_sol_pos(double&,double&);
  double give_Rsun()  {return Rsun;}
  double give_zsun()  {return zsun;}
  void give_vc(double&);
  double give_vcsun() {return vcsun;}
  void give_vsol(double&,double&,double&);
  void give_epoch(double&);

  vec6  give_HEQ() {return give(0);}  vec6  give_HGP() {return give(1);}
  vec6  give_HCA() {return give(2);}  vec6  give_LSR() {return give(3);}
  vec6  give_GCA() {return give(4);}  vec6  give_GCY() {return give(5);}
  vec6  give_HEQ_units() {return give_units(0);}
  vec6  give_HGP_units() {return give_units(1);}
  vec6  give_HCA_units() {return give_units(2);}
  vec6  give_LSR_units() {return give_units(3);}
  vec6  give_GCA_units() {return give_units(4);}
  vec6  give_GCY_units() {return give_units(5);}
  vec6  give(int);
  vec6  give_units(int);
  void  take_HEQ(vec6);  void  take_HGP(vec6);  void  take_HCA(vec6);
  void  take_LSR(vec6);  void  take_GCA(vec6);  void  take_GCY(vec6);
  void  take_HEQ_units(vec6);  void  take_HGP_units(vec6);
  void  take_HCA_units(vec6);  void  take_LSR_units(vec6);
  void  take_GCA_units(vec6);  void  take_GCY_units(vec6);

  // Just want to convert. No fannying about.
  vec6 HEQfromHGP(vec6 sHGP) {take_HGP(sHGP); return give_HEQ();}
  vec6 HEQfromHCA(vec6 sHCA) {take_HCA(sHCA); return give_HEQ();}
  vec6 HEQfromLSR(vec6 sLSR) {take_LSR(sLSR); return give_HEQ();}
  vec6 HEQfromGCA(vec6 sGCA) {take_GCA(sGCA); return give_HEQ();}
  vec6 HEQfromGCY(vec6 sGCY) {take_GCY(sGCY); return give_HEQ();}

  vec6 HGPfromHEQ(vec6 sHEQ) {take_HEQ(sHEQ); return give_HGP();}
  vec6 HGPfromHCA(vec6 sHCA) {take_HCA(sHCA); return give_HGP();}
  vec6 HGPfromLSR(vec6 sLSR) {take_LSR(sLSR); return give_HGP();}
  vec6 HGPfromGCA(vec6 sGCA) {take_GCA(sGCA); return give_HGP();}
  vec6 HGPfromGCY(vec6 sGCY) {take_GCY(sGCY); return give_HGP();}

  vec6 HCAfromHEQ(vec6 sHEQ) {take_HEQ(sHEQ); return give_HCA();}
  vec6 HCAfromHGP(vec6 sHGP) {take_HGP(sHGP); return give_HCA();}
  vec6 HCAfromLSR(vec6 sLSR) {take_LSR(sLSR); return give_HCA();}
  vec6 HCAfromGCA(vec6 sGCA) {take_GCA(sGCA); return give_HCA();}
  vec6 HCAfromGCY(vec6 sGCY) {take_GCY(sGCY); return give_HCA();}

  vec6 LSRfromHEQ(vec6 sHEQ) {take_HEQ(sHEQ); return give_LSR();}
  vec6 LSRfromHGP(vec6 sHGP) {take_HGP(sHGP); return give_LSR();}
  vec6 LSRfromHCA(vec6 sHCA) {take_HCA(sHCA); return give_LSR();}
  vec6 LSRfromGCA(vec6 sGCA) {take_GCA(sGCA); return give_LSR();}
  vec6 LSRfromGCY(vec6 sGCY) {take_GCY(sGCY); return give_LSR();}

  vec6 GCAfromHEQ(vec6 sHEQ) {take_HEQ(sHEQ); return give_GCA();}
  vec6 GCAfromHGP(vec6 sHGP) {take_HGP(sHGP); return give_GCA();}
  vec6 GCAfromHCA(vec6 sHCA) {take_HCA(sHCA); return give_GCA();}
  vec6 GCAfromLSR(vec6 sLSR) {take_LSR(sLSR); return give_GCA();}
  vec6 GCAfromGCY(vec6 sGCY) {take_GCY(sGCY); return give_GCA();}

  vec6 GCYfromHEQ(vec6 sHEQ) {take_HEQ(sHEQ); return give_GCY();}
  vec6 GCYfromHGP(vec6 sHGP) {take_HGP(sHGP); return give_GCY();}
  vec6 GCYfromHCA(vec6 sHCA) {take_HCA(sHCA); return give_GCY();}
  vec6 GCYfromLSR(vec6 sLSR) {take_LSR(sLSR); return give_GCY();}
  vec6 GCYfromGCA(vec6 sGCA) {take_GCA(sGCA); return give_GCY();}

  OmniCoords() ;
  ~OmniCoords() {};
};

inline OmniCoords::OmniCoords() {
  know = false;
  Rsun = GalactoConstants::Rsun; zsun = GalactoConstants::zsun; vcsun = GalactoConstants::vcsun;
  Usun = GalactoConstants::usun; Vsun = GalactoConstants::vsun; Wsun  = GalactoConstants::wsun;
  epoch = 2000.;
  SetTrans();
}

inline void OmniCoords::take_HEQ(vec6 tHEQ) {
  rv[0] = tHEQ; know = false; know[0] = true;
}
inline void OmniCoords::take_HEQ_units(vec6 tHEQ) {
  vec6 tmp = tHEQ;
  tmp[1] *=Units::degree;
  tmp[2] *=Units::degree;
  tmp[3] *=Units::kms;
  tmp[4] *=Units::masyr;
  tmp[5] *=Units::masyr;
  rv[0] = tmp; know = false; know[0] = true;
}
inline void OmniCoords::take_HGP(vec6 tHGP) {
  rv[1] = tHGP; know = false; know[1] = true;
}
inline void OmniCoords::take_HGP_units(vec6 tHGP) {
  vec6 tmp = tHGP;
  tmp[1] *=Units::degree;
  tmp[2] *=Units::degree;
  tmp[3] *=Units::kms;
  tmp[4] *=Units::masyr;
  tmp[5] *=Units::masyr;
  rv[1] = tmp; know = false; know[1] = true;
}

inline void OmniCoords::take_HCA(vec6 tHCA) {
  rv[2] = tHCA; know = false; know[2] = true;
}
inline void OmniCoords::take_HCA_units(vec6 tHCA) {
  vec6 tmp = tHCA;
  for(int i=3;i!=6;i++) tmp[i] *= Units::kms;
  rv[2] = tmp; know = false; know[2] = true;
}

inline void OmniCoords::take_LSR(vec6 tLSR) {
  rv[3] = tLSR; know = false; know[3] = true;
}
inline void OmniCoords::take_LSR_units(vec6 tLSR) {
  vec6 tmp = tLSR;
  for(int i=3;i!=6;i++) tmp[i] *= Units::kms;
  rv[3] = tmp; know = false; know[3] = true;
}

inline void OmniCoords::take_GCA(vec6 tGCA) {
  rv[4] = tGCA; know = false; know[4] = true;
}
inline void OmniCoords::take_GCA_units(vec6 tGCA) {
  vec6 tmp = tGCA;
  for(int i=3;i!=6;i++) tmp[i] *= Units::kms;
  rv[4] = tmp; know = false; know[4] = true;
}

inline void OmniCoords::take_GCY(vec6 tGCY) {
  rv[5] = tGCY; know = false; know[5] = true;
}
inline void OmniCoords::take_GCY_units(vec6 tGCY) {
  vec6 tmp = tGCY;
  tmp[2] *= Units::degree;
  for(int i=3;i!=6;i++) tmp[i] *= Units::kms;
  rv[5] = tmp; know = false; know[5] = true;
}

inline void OmniCoords::Backward(int n) {
  switch(n) {
  case 0 :
    HEQfromHCA(); break;
  case 1 :
    HGPfromHCA(); break;
  case 2 :
    HCAfromLSR(); break;
  case 3 :
    LSRfromGCA(); break;
  case 4 :
    GCAfromGCY(); break;
  default :
    cerr << "dude what?\n";
  }
}

inline void OmniCoords::Forward(int n) {
  switch(n) {
  case 0 :
    HCAfromHEQ();break;
  case 1 :
    HCAfromHGP(); break;
  case 2 :
    LSRfromHCA();break;
  case 3 :
    GCAfromLSR(); break;
  case 4 :
    GCYfromGCA();break;
  default :
    cerr << "dude what?\n";
  }
}

inline vec6 OmniCoords::give(int n) {
  if(know[n]) return rv[n]; // if known, give

  if(n==0) {                // special case, because HEQ found from HCA not
    bool found = false;     //  from HGP.
    for(int i=2;i<=5 && !found;i++)
      if(know[i]) {
	for(int j=i;j>1;j--) Backward(j);
	found = true;
      }
    Backward(0);
    return rv[n];
  }
  for(int i=n-1;i>=1;i--)    // if 'earlier' are known
    if(know[i]) {
      for(int j=i;j<n;j++) Forward(j);
      return rv[n];
    }

  for(int i=n+1;i<=5;i++)   // if 'later' are known
    if(know[i]) {
      for(int j=i-1;j>=n;j--) Backward(j);
      return rv[n];
    }

  if(know[0]) {
    Forward(0);
    if(n==1) Backward(1);
    else for(int i=2;i<n;i++) Forward(i);
    return rv[n];
  }
  cerr << "No input set\n";
  return vec6(0.);
}

inline vec6 OmniCoords::give_units(int n) {
  vec6 coords = give(n);
  if(n>1) {
    for(int i=3;i!=6;i++) coords[i] *= Units::kms_i;
    if(n==5) coords[2] *= Units::degree_i;
    return coords;
  }
  coords[1] *=Units::degree_i;
  coords[2] *=Units::degree_i;
  coords[3] *=Units::kms_i;
  coords[4] *=Units::masyr_i;
  coords[5] *=Units::masyr_i;
  return coords;
}

inline void OmniCoords::change_vc(double vc) {
  vcsun = vc; know = false;
  if(vcsun>0.)
    cerr << "Careful: You have set vc_sun>0, which is not the norm\n";
}
inline void OmniCoords::change_sol_pos(double R, double z) {
  Rsun = R; zsun = z; know = false;
}
inline void OmniCoords::change_vsol(double U, double V, double W) {
  Usun = U; Vsun=V; Wsun=W; know = false;
}

inline void OmniCoords::change_epoch(double ep) {
  epoch = ep; SetTrans(); know = false;
}

inline void OmniCoords::give_vc(double& vc) {
 vcsun = vc;
}
inline void OmniCoords::give_sol_pos(double& R, double& z) {
  R = Rsun; z = zsun;
}
inline void OmniCoords::give_vsol(double& U, double& V, double& W) {
  U=Usun; V=Vsun; W=Wsun;
}
inline void OmniCoords::give_epoch(double& ep) {
  ep=epoch;
}

inline void OmniCoords::set_SBD10() {
  change_vsol(11.1*Units::kms,12.24*Units::kms,7.25*Units::kms);
}

inline void OmniCoords::set_DB98() {
  change_vsol(10.*Units::kms,5.25*Units::kms,7.17*Units::kms);
}

#endif


text:
<TITLE>Review for Road to Glory (2000)</TITLE>
<LINK REL="STYLESHEET" TYPE="text/css" HREF="/ramr.css">

Road to Glory (2000)

reviewed by
Mark R. Leeper

                                THE CUP
                    A film review by Mark R. Leeper

               Capsule: The first film from Bhutan will win
          no prizes for inventive plotting.  In a Tibetan
          monastery in exile in India the mischievous young
          monks want to break with centuries of tradition and
          to see the World Cup Championship.  The plot is new
          packaging for old plot elements.  Not all of the
          messages of this film were necessarily intended.
          Rating: 6 (0 to 10), +1 (-4 to +4)

     Typically the first film from a filmmaker or from a country is a
simple one.  One starts with baby steps and learns to walk before one
can run.  Directed and written by Khyentse Norbu, THE CUP is a simple
little story of a tiny piece of the outside world coming to a Tibetan
monastery in exile in Northern India.

     The film opens showing the daily life in a Tibetan monastery.  It
may not be intended but the primary message of these scenes is that the
life of a monk is one of monotony that would drive the rest of us
crazy.  At least there are interesting characters to flesh out the
tedium like a monastery soothsayer who gets little respect from anyone.
In the daily routine there is cooking and prayer and occasional
exercise. Nothing drives home the monotony better than a scene in which
visitors have arrived.  The abbot and some high monks talk to them.
The monks are in the traditional yellow and maroon robes.  The curtains
are in the same yellow as the robes, the luggage is in the same maroon.
One's eye searches in vain for a break in the color scheme.

     The young monks like to play football with anything available. The
quality of life would seem to be stultifyingly dull if it were not for
the young monks' interest in football.  In the case we see it is a Coke
can.  The monks paste on their walls pictures of their football heroes.
Four of the young monks even sneak into town to watch the semi-finals
on TV.  This is all done under the stern but loving eye of Geko (Orgyen
Tobgyal), sort of the vice-principal or house-father of the monastery.
One of the new arrivals gets an idea that perhaps they can rent a TV
and an antenna and see the World Cup Finals from the monastery.  The
question is taken to the old abbot who does not seem to quite
understand the concept of a game.  (He must indeed be and old man to
have forgotten games.  The young monks play them all the time.)

     When the abbot agrees there are but ten hours until the game will
be on.  In that time there are several obstacles to be overcome.  First
of all there is the question of how to pay for the rental.  The must
figure how to move the dish.  Once they have it they must set it up
with no technical experience.  There are come complications as the
greed of the TV dealer almost ruins the night for the young monk who
planned it.  He scalps what money he can from the young monks and
misdirects them.  Norbu seems less than respectful toward Indians.

     The plot of kids sneaking out of boarding school and getting into
trouble has been a staple of films going back at least to silent film.
So have head masters who seemed gruff disciplinarians but at heart love
their charges and are old softies.  Certainly the revelation that holy
people can be interested in something as mundane as sports is not
original either.  In a film from any other origins with this plot would
seem cliched.  Norbu does not give us any new slant beyond the setting.
This is a film that is moderately entertaining but not very original at
all.

     It is, however, the very first feature film from Bhutan.  It might
be fairer to say that it is a Bhutan-Australia co-production.  To
paraphrase Dr. Johnson, it is not Norbu has made a great film, it is
just interesting that Bhutan has made a film at all.  Here Norbu has
given us enough of a look into the daily life of a Tibetan monk to
convince us that that life is not for most of us.  And he has told us a
small, simple, likable story.  The story is based on a real incident we
are told, though the copyright notice at the end denies it.  Still as a
film from Bhutan, it is a good start.  Welcome to the majors.  I rate
it a 6 on the 0 to 10 scale and a +1 on the -4 to +4 scale.

                                        Mark R. Leeper
                                        mleeper@lucent.com
                                        Copyright 2000 Mark R. Leeper

The review above was posted to the
rec.arts.movies.reviews newsgroup (de.rec.film.kritiken for German reviews).

The Internet Movie Database accepts no responsibility for the contents of the
review and has no editorial control. Unless stated otherwise, the copyright
belongs to the author.

Please direct comments/criticisms of the review to relevant newsgroups.

Broken URLs inthe reviews are the responsibility of the author.

The formatting of the review is likely to differ from the original due
to ASCII to HTML conversion.

Related links: index of all rec.arts.movies.reviews reviews

redpajama_set_name: RedPajamaGithub


text:
import {
  Component,
  ChangeDetectionStrategy,
  Input,
  HostBinding,
  Output,
  EventEmitter,
  ChangeDetectorRef,
  OnDestroy,
  OnInit,
} from '@angular/core';
import { getDefaultStateForInputType } from './input-card.utils';
import { ICON_STYLE_CLASSES, IconStyle } from 'cd-themes';
import { Subject, Subscription } from 'rxjs';
import { debounceTime } from 'rxjs/operators';
import { clamp } from 'cd-utils/numeric';
import { toCamelCase, trimChar } from 'cd-utils/string';
import * as consts from 'cd-common/consts';
import * as config from '../../code-comp.config';
import * as utils from 'cd-common/utils';
import * as cd from 'cd-interfaces';

const UNLABELED_INPUT_NAME = 'Unlabeled';

@Component({
  selector: 'app-input-card',
  templateUrl: './input-card.component.html',
  styleUrls: ['./input-card.component.scss'],
  changeDetection: ChangeDetectionStrategy.OnPush,
})
export class InputCardComponent implements OnDestroy, OnInit {
  private _subscription = new Subscription();
  private _nameValidation$ = new Subject<string>();
  private _nameWasEdited = false;

  public PropertyInput = cd.PropertyInput;
  public BindingType = cd.BindingType;
  public UNLABELED_INPUT_NAME = UNLABELED_INPUT_NAME;
  public INPUT_TYPES_MENU_DATA = config.INPUT_TYPES_MENU_DATA;
  public INPUT_BINDING_TYPES_MENU_DATA = config.INPUT_BINDING_TYPES_MENU_DATA;
  public iconClass = ICON_STYLE_CLASSES[IconStyle.MATERIAL_ICONS_FILLED];
  public inputTypeHelpText: cd.IRichTooltip = { text: config.INPUT_TYPE_TEXT };
  public inputCssNameHelpText: cd.IRichTooltip = { text: config.INPUT_CSS_NAME_TEXT };
  public inputPropAttrNameHelpText: cd.IRichTooltip = { text: config.INPUT_PROP_ATTR_NAME_TEXT };
  public color?: cd.IValue;
  public nameErrorText?: cd.IRichTooltip;
  public dataToAttributeErrorText?: cd.IRichTooltip;

  @Input() colorMenuData: ReadonlyArray<cd.ISelectItem> = [];
  @Input() datasetsMenuItems: cd.ISelectItem[] = [];
  @Input() colors: cd.IStringMap<cd.IDesignColor> = {};
  @Input() input?: Readonly<cd.IPropertyGroup>;
  @Input() allInputs?: ReadonlyArray<cd.IPropertyGroup> = [];
  @Input() allOutputs?: ReadonlyArray<cd.IOutputProperty> = [];

  @Input()
  @HostBinding('class.drag-preview')
  previewCard = false;

  @Output() update = new EventEmitter<cd.IPropertyGroup>();
  @Output() delete = new EventEmitter<void>();

  constructor(private _cdRef: ChangeDetectorRef) {}

  ngOnInit(): void {
    const validName$ = this._nameValidation$.pipe(
      debounceTime(consts.INPUT_VALIDATION_DEBOUNCE_TIME)
    );
    this._subscription.add(validName$.subscribe(this.validateName));
  }

  ngOnDestroy() {
    this._subscription.unsubscribe();
  }

  get canShowContents(): boolean {
    return !this.previewCard && !this.collapsed;
  }

  get nameValue(): string {
    return this.input?.name || '';
  }

  get labelValue(): string {
    return this.input?.label || '';
  }

  get collapsed(): boolean | undefined {
    return this.input?.collapsed;
  }

  /**
   * Should auto-generate the name on label change if:
   * 1) User had not yet edited the name and ...
   * 2) Name is empty -or- name is still the default "myInput"
   */
  get shouldAutogenName(): boolean {
    if (!this.input?.name) return true;
    const defaultName = config.DEFAULT_NEW_INPUT.name as string;
    const hasDefaultName = this.toCamelCaseInputName(this.input?.name).startsWith(defaultName);
    return !this._nameWasEdited && hasDefaultName;
  }

  onDelete() {
    this.delete.emit();
  }

  onLabelChange(label: string) {
    let name = this.input?.name;

    // Auto-generate default name based on label
    if (label && this.shouldAutogenName) {
      name = this.autoGenerateName(label, this.input?.bindingType);
    }

    const update = { ...this.input, name, label };
    this.update.emit(update);
  }

  onNameChange(name: string) {
    const bindingType = this.input?.bindingType;
    const isValid =
      this.validateDuplicateInputName(name, bindingType) || this.validateName(name, bindingType);
    if (!isValid || this.nameValue === name) return;
    const update = { ...this.input, name };
    this.update.emit(update);
    this._nameWasEdited = true;
  }

  onTypeChange(item: cd.ISelectItem) {
    const inputType = item.value as cd.PropertyInput;
    const isValid = this.validateInputAndBindingType(inputType, this.input?.bindingType);
    if (!isValid) return;
    const defaultState = getDefaultStateForInputType(inputType);
    const update = { ...this.input, ...defaultState, inputType };
    this.update.emit(update);
  }

  onBindingTypeChange(item: cd.ISelectItem) {
    const bindingType = item.value as cd.BindingType;
    let name = this.input?.name as string;

    // Convert name between camelCase and --css-var format
    if (!this._nameWasEdited && name) {
      name = this.autoGenerateName(name, bindingType);
    }

    const isValid =
      this.validateInputAndBindingType(this.input?.inputType, bindingType) &&
      this.validateName(name, bindingType);

    if (!isValid) return;
    const update = { ...this.input, name, bindingType };
    this.update.emit(update);
  }

  toggleCollapsed() {
    const collapsed = !this.input?.collapsed;
    const update = { ...this.input, collapsed };
    this.update.emit(update);
  }

  updateDefaultValue(defaultValue: cd.PropertyValue) {
    const updatedInput = { ...this.input, defaultValue };
    this.update.emit(updatedInput);
  }

  // Checkbox Updates
  onCheckboxChange(value: boolean) {
    this.updateDefaultValue(value);
  }

  // Color updates
  onColorChange(value: string | cd.ISelectItem) {
    // If binding is CSS variable and value is an ISelectItem, convert to IValue
    // Otherwise, use raw string type for property/attribute bindings
    const isCSSVar = utils.isIValue(value) && this.input?.bindingType === cd.BindingType.CssVar;
    const processed = isCSSVar ? utils.iValueFromAny(value) : utils.valueFromIValue(value);
    this.updateDefaultValue(processed);
  }

  // Number update
  onNumberChange(num: number) {
    this.updateDefaultValue(num);
  }

  // Range updates
  onMinChange(min: number) {
    const { input } = this;
    if (!input) return;
    const max = input.max ?? 0;
    if (min > max) min = max; // prevent min from being greater than max
    const defaultValue = this.clampDefaultValue(input.defaultValue, min, max);
    const update = { ...input, min, defaultValue };
    this.update.emit(update);
  }

  clampDefaultValue(
    value: cd.PropertyValue | undefined,
    min: number,
    max: number
  ): number | undefined {
    return value === undefined ? value : clamp(Number(value), min, max);
  }

  onMaxChange(max: number) {
    const { input } = this;
    if (!input) return;
    const min = input.min ?? 0;
    if (max < min) max = min; // prevent max from being less than min
    const defaultValue = this.clampDefaultValue(input.defaultValue, min, max);
    const update = { ...input, max, defaultValue };
    this.update.emit(update);
  }

  onRangeChange(value: number) {
    this.updateDefaultValue(value);
  }

  // Text update
  onTextChange(text: string) {
    this.updateDefaultValue(text);
  }

  // Icon update
  onIconChange(iconName: string) {
    this.updateDefaultValue(iconName);
  }

  // dataset update
  onDatasetChange(datasetItem: cd.ISelectItem) {
    this.updateDefaultValue(datasetItem.value);
  }

  requestNameValidation(inputEvent: Event) {
    const { value } = inputEvent.target as HTMLInputElement;
    this._nameValidation$.next(value);
  }

  /** Check to ensure name is not empty, and matches the correct pattern. */
  private validateName = (name: string, bindingType?: cd.BindingType): boolean => {
    let isValid = true;
    const isCssVar = (bindingType || this.input?.bindingType) === cd.BindingType.CssVar;

    // Skip validation if setting name back to initial value
    if (this.nameValue === name) {
      this.nameErrorText = undefined;
    }
    // Check if name is defined
    if (!name) {
      isValid = false;
      this.nameErrorText = isCssVar
        ? config.NO_CSS_VAR_NAME_ERROR_TEXT
        : config.NO_INPUT_NAME_ERROR_TEXT;
    }
    // Check if name is a valid CSS var pattern
    else if (isCssVar && !utils.validateCssVarName(name)) {
      isValid = false;
      this.nameErrorText = config.getInvalidNameErrorText(name, config.NameErrorType.CssVar);
    }
    // Check if name is a valid input name
    else if (!isCssVar && !utils.validateInputOutputName(name)) {
      isValid = false;
      this.nameErrorText = config.getInvalidNameErrorText(name, config.NameErrorType.Input);
    }
    // Else remove error state from input
    else {
      this.nameErrorText = undefined;
    }

    this._cdRef.markForCheck();
    return isValid;
  };

  /**
   * Check to ensure that we don't assign Data input type to Attribute binding.
   * Attributes are always strings, so assigning data to an attribute wont work.
   */
  private validateInputAndBindingType = (
    inputType?: cd.PropertyInput,
    bindingType?: cd.BindingType
  ): boolean => {
    const isAttribute = bindingType && bindingType === cd.BindingType.Attribute;
    const isDataSelect = inputType && inputType === cd.PropertyInput.DatasetSelect;
    const isValid = !(isAttribute === true && isDataSelect === true);
    this.dataToAttributeErrorText = isValid ? undefined : config.DATA_BOUND_TO_ATTRIBUTE_ERROR_TEXT;
    this._cdRef.markForCheck();
    return isValid;
  };

  /** Check if name is a duplicate of an existing input or output name. */
  private validateDuplicateInputName(name: string, bindingType?: cd.BindingType): boolean {
    const isValid = utils.checkIfDuplicateInputOutputName(name, this.allInputs, this.allOutputs);

    if (isValid) return true;
    const isCSSVar = bindingType === cd.BindingType.CssVar;
    const nameErrorType = isCSSVar ? config.NameErrorType.CssVar : config.NameErrorType.Input;
    this.nameErrorText = config.getDuplicateNameErrorText(name, nameErrorType);
    return false;
  }

  /** Converts to camelCase, but accounts for possible CSS var prefix "--". */
  private toCamelCaseInputName(name: string) {
    return toCamelCase(trimChar('-', name));
  }

  /** Auto-generates the property name based on the label and bindingType. */
  private autoGenerateName(label: string, bindingType?: cd.BindingType): string {
    const isCssVar = bindingType === cd.BindingType.CssVar;
    // Create name in --css-var-format if CSS var
    if (isCssVar) return utils.toCssVarName(label);
    // Create name in camelCase if attribute/property
    return this.toCamelCaseInputName(label);
  }
}


text:
namespace ofxLaser {
class ColourSettings {

    public :

    ColourSettings();

    float calculateCalibratedBrightness(float value, float intensity, float level100, float level75, float level50, float level25, float level0);
    void processColour(ofxLaser::Point& p, float brightness);

    // would probably be sensible to move these settings out into a colour
    // calibration object.
    ofParameterGroup params;

    ofParameter<float>red100;
    ofParameter<float>red75;
    ofParameter<float>red50;
    ofParameter<float>red25;
    ofParameter<float>red0;

    ofParameter<float>green100;
    ofParameter<float>green75;
    ofParameter<float>green50;
    ofParameter<float>green25;
    ofParameter<float>green0;

    ofParameter<float>blue100;
    ofParameter<float>blue75;
    ofParameter<float>blue50;
    ofParameter<float>blue25;
    ofParameter<float>blue0;

};
}


text:
@implementation HomeController

@synthesize userIdField, emailField, firstnameField, lastnameField, logoutButton;

- (void)didReceiveMemoryWarning
{
    // Releases the view if it doesn't have a superview.
    [super didReceiveMemoryWarning];

    // Release any cached data, images, etc that aren't in use.
}

- (IBAction)logoutPressed:(UIButton *)sender
{
    [[AppUser sharedAppUser] logout];
    [self.navigationController popViewControllerAnimated:YES];
}

#pragma mark - View lifecycle

- (void)releaseOutlets
{
    [userIdField release];
    [emailField release];
    [firstnameField release];
    [lastnameField release];
    [logoutButton release];
}

- (void)viewDidLoad
{
    [super viewDidLoad];
    // Do any additional setup after loading the view from its nib.
    AppUser *user = [AppUser sharedAppUser];
    [userIdField setText:[[user userId] stringValue]];
    [emailField setText:([[user email] isEqual:[NSNull null]]) ? @"" : [user email]];
    [firstnameField setText:([[user firstname] isEqual:[NSNull null]]) ? @"" : [user firstname]];
    [lastnameField setText:([[user lastname] isEqual:[NSNull null]]) ? @"" : [user lastname]];
}

- (void)viewDidUnload
{
    [super viewDidUnload];
    // Release any retained subviews of the main view.
    // e.g. self.myOutlet = nil;
    [self releaseOutlets];
}

- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
{
    // Return YES for supported orientations
    return (interfaceOrientation == UIInterfaceOrientationPortrait);
}

@end


text:
package org.workcraft.plugins.interop;

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;

import org.apache.batik.transcoder.Transcoder;
import org.apache.batik.transcoder.TranscoderException;
import org.apache.batik.transcoder.TranscoderInput;
import org.apache.batik.transcoder.TranscoderOutput;
import org.apache.batik.transcoder.image.PNGTranscoder;
import org.workcraft.dom.Model;
import org.workcraft.dom.visual.VisualModel;
import org.workcraft.exceptions.SerialisationException;
import org.workcraft.interop.Exporter;

public class PngExporter implements Exporter {

    @Override
    public void export(Model model, OutputStream out) throws IOException, SerialisationException {
        InputStream svg = SvgExportUtils.stream(model);
        Transcoder transcoder = new PNGTranscoder();
        TranscoderInput transcoderInput = new TranscoderInput(svg);
        TranscoderOutput transcoderOutput = new TranscoderOutput(out);
        try {
            transcoder.transcode(transcoderInput, transcoderOutput);
        } catch (TranscoderException e) {
            throw new SerialisationException(e);
        }
    }

    @Override
    public int getCompatibility(Model model) {
        if (model instanceof VisualModel) {
            return Exporter.GENERAL_COMPATIBILITY;
        } else {
            return Exporter.NOT_COMPATIBLE;
        }
    }

    @Override
    public PngFormat getFormat() {
        return PngFormat.getInstance();
    }

}


text:
class CreateCompanies < ActiveRecord::Migration
  def self.up
    create_table :companies do |t|
      t.string :name, :size => 50
      t.string :address1, :size => 100
      t.string :address2, :size => 100
      t.integer :locality_id
      t.integer :city_id
      t.string :state, :size => 50
      t.string :country, :size => 50
      t.string :pincode, :size => 7
      t.string :phone1, :size => 15
      t.string :phone2, :size => 15
      t.string :fax, :size => 15
      t.string :email, :size => 50
      t.string :contact, :size => 50
      t.text :about
      t.integer :business_id

      t.timestamps
    end
    add_index :companies, :locality_id
    add_index :companies, :city_id
    add_index :companies, :business_id
    add_index :companies, :pincode
    add_index :companies, :address1
    add_index :companies, :address2
    add_index :companies, :name
  end

  def self.down
    drop_table :companies
    remove_index :companies, :locality_id
    remove_index :companies, :city_id
    remove_index :companies, :business_id
    remove_index :companies, :pincode
    remove_index :companies, :address1
    remove_index :companies, :address2
    remove_index :companies, :name
  end
end


text:
"""
Encoders for sequence-to-sequence models.
"""
import inspect
import logging
from abc import ABC, abstractmethod
from math import ceil, floor
from typing import Callable, List, Optional, Tuple, Union, Dict

import mxnet as mx

from . import config
from . import constants as C
from . import convolution
from . import rnn
from . import transformer
from . import utils

logger = logging.getLogger(__name__)

ImageEncoderConfig = None

def get_encoder(config: 'EncoderConfig', prefix: str = '') -> 'Encoder':
    if isinstance(config, RecurrentEncoderConfig):
        return get_recurrent_encoder(config, prefix)
    elif isinstance(config, transformer.TransformerConfig):
        return get_transformer_encoder(config, prefix)
    elif isinstance(config, ConvolutionalEncoderConfig):
        return get_convolutional_encoder(config, prefix)
    elif isinstance(config, EmptyEncoderConfig):
        return EncoderSequence([EmptyEncoder(config)], config.dtype)
    else:
        from .image_captioning.encoder import ImageLoadedCnnEncoderConfig, \
            get_image_cnn_encoder

        if isinstance(config, ImageLoadedCnnEncoderConfig):
            return get_image_cnn_encoder(config)
        else:
            raise ValueError("Unsupported encoder configuration")

class RecurrentEncoderConfig(config.Config):
    """
    Recurrent encoder configuration.

    :param rnn_config: RNN configuration.
    :param conv_config: Optional configuration for convolutional embedding.
    :param reverse_input: Reverse embedding sequence before feeding into RNN.
    :param dtype: Data type.
    """

    def __init__(self,
                 rnn_config: rnn.RNNConfig,
                 conv_config: Optional['ConvolutionalEmbeddingConfig'] = None,
                 reverse_input: bool = False,
                 dtype: str = C.DTYPE_FP32) -> None:
        super().__init__()
        self.rnn_config = rnn_config
        self.conv_config = conv_config
        self.reverse_input = reverse_input
        self.dtype = dtype

class ConvolutionalEncoderConfig(config.Config):
    """
    Convolutional encoder configuration.

    :param cnn_config: CNN configuration.
    :param num_layers: The number of convolutional layers on top of the embeddings.
    :param positional_embedding_type: The type of positional embedding.
    :param dtype: Data type.
    """

    def __init__(self,
                 num_embed: int,
                 max_seq_len_source: int,
                 cnn_config: convolution.ConvolutionConfig,
                 num_layers: int,
                 positional_embedding_type: str,
                 dtype: str = C.DTYPE_FP32) -> None:
        super().__init__()
        self.num_embed = num_embed
        self.num_layers = num_layers
        self.cnn_config = cnn_config
        self.max_seq_len_source = max_seq_len_source
        self.positional_embedding_type = positional_embedding_type
        self.dtype = dtype

class EmptyEncoderConfig(config.Config):
    """
    Empty encoder configuration.
    :param num_embed: source embedding size.
    :param num_hidden: the representation size of this encoder.
    :param dtype: Data type.
    """

    def __init__(self,
                 num_embed: int,
                 num_hidden: int,
                 dtype: str = C.DTYPE_FP32) -> None:
        super().__init__()
        self.num_embed = num_embed
        self.num_hidden = num_hidden
        self.dtype = dtype
        self.allow_missing = True

def get_recurrent_encoder(config: RecurrentEncoderConfig, prefix: str) -> 'Encoder':
    """
    Returns an encoder stack with a bi-directional RNN, and a variable number of uni-directional forward RNNs.

    :param config: Configuration for recurrent encoder.
    :param prefix: Prefix for variable names.
    :return: Encoder instance.
    """
    # TODO give more control on encoder architecture
    encoder_seq = EncoderSequence([], config.dtype)

    if config.conv_config is not None:
        encoder_seq.append(ConvolutionalEmbeddingEncoder, config=config.conv_config,
                           prefix=prefix + C.CHAR_SEQ_ENCODER_PREFIX)
        if config.conv_config.add_positional_encoding:
            # If specified, add positional encodings to segment embeddings
            encoder_seq.append(AddSinCosPositionalEmbeddings,
                               num_embed=config.conv_config.num_embed,
                               scale_up_input=False,
                               scale_down_positions=False,
                               prefix="%s%sadd_positional_encodings" % (prefix, C.CHAR_SEQ_ENCODER_PREFIX))
        encoder_seq.append(ConvertLayout, infer_hidden=True, target_layout=C.TIME_MAJOR)
    else:
        encoder_seq.append(ConvertLayout, target_layout=C.TIME_MAJOR, num_hidden=0)

    if config.reverse_input:
        encoder_seq.append(ReverseSequence, infer_hidden=True)

    if config.rnn_config.residual:
        utils.check_condition(config.rnn_config.first_residual_layer >= 2,
                              "Residual connections on the first encoder layer are not supported")

    # One layer bi-directional RNN:
    encoder_seq.append(BiDirectionalRNNEncoder,
                       rnn_config=config.rnn_config.copy(num_layers=1),
                       prefix=prefix + C.BIDIRECTIONALRNN_PREFIX,
                       layout=C.TIME_MAJOR)

    if config.rnn_config.num_layers > 1:
        # Stacked uni-directional RNN:
        # Because we already have a one layer bi-rnn we reduce the num_layers as well as the first_residual_layer.
        remaining_rnn_config = config.rnn_config.copy(num_layers=config.rnn_config.num_layers - 1,
                                                      first_residual_layer=config.rnn_config.first_residual_layer - 1)
        encoder_seq.append(RecurrentEncoder,
                           rnn_config=remaining_rnn_config,
                           prefix=prefix + C.STACKEDRNN_PREFIX,
                           layout=C.TIME_MAJOR)

    encoder_seq.append(ConvertLayout, infer_hidden=True, target_layout=C.BATCH_MAJOR)

    return encoder_seq

def get_convolutional_encoder(config: ConvolutionalEncoderConfig, prefix: str) -> 'Encoder':
    """
    Creates a convolutional encoder.

    :param config: Configuration for convolutional encoder.
    :param prefix: Prefix for variable names.
    :return: Encoder instance.
    """
    encoder_seq = EncoderSequence([], dtype=config.dtype)
    cls, encoder_params = _get_positional_embedding_params(config.positional_embedding_type,
                                                           config.num_embed,
                                                           max_seq_len=config.max_seq_len_source,
                                                           fixed_pos_embed_scale_up_input=False,
                                                           fixed_pos_embed_scale_down_positions=True,
                                                           prefix=prefix + C.SOURCE_POSITIONAL_EMBEDDING_PREFIX)
    encoder_seq.append(cls, **encoder_params)
    encoder_seq.append(ConvolutionalEncoder, config=config)
    return encoder_seq

def get_transformer_encoder(config: transformer.TransformerConfig, prefix: str) -> 'Encoder':
    """
    Returns a Transformer encoder, consisting of an embedding layer with
    positional encodings and a TransformerEncoder instance.

    :param config: Configuration for transformer encoder.
    :param prefix: Prefix for variable names.
    :return: Encoder instance.
    """
    encoder_seq = EncoderSequence([], dtype=config.dtype)
    cls, encoder_params = _get_positional_embedding_params(config.positional_embedding_type,
                                                           config.model_size,
                                                           config.max_seq_len_source,
                                                           fixed_pos_embed_scale_up_input=True,
                                                           fixed_pos_embed_scale_down_positions=False,
                                                           prefix=prefix + C.SOURCE_POSITIONAL_EMBEDDING_PREFIX)
    encoder_seq.append(cls, **encoder_params)
    if config.conv_config is not None:
        encoder_seq.append(ConvolutionalEmbeddingEncoder, config=config.conv_config,
                           prefix=prefix + C.CHAR_SEQ_ENCODER_PREFIX)

    encoder_seq.append(TransformerEncoder, config=config, prefix=prefix + C.TRANSFORMER_ENCODER_PREFIX)

    return encoder_seq

class Encoder(ABC):
    """
    Generic encoder interface.

    :param dtype: Data type.
    """

    @abstractmethod
    def __init__(self, dtype):
        logger.info('{}.{} dtype: {}'.format(self.__module__, self.__class__.__name__, dtype))
        self.dtype = dtype

    @abstractmethod
    def encode(self,
               data: mx.sym.Symbol,
               data_length: Optional[mx.sym.Symbol],
               seq_len: int) -> Tuple[mx.sym.Symbol, mx.sym.Symbol, int]:
        """
        Encodes data given sequence lengths of individual examples and maximum sequence length.

        :param data: Input data.
        :param data_length: Vector with sequence lengths.
        :param seq_len: Maximum sequence length.
        :return: Encoded versions of input data (data, data_length, seq_len).
        """
        pass

    @abstractmethod
    def get_num_hidden(self) -> int:
        """
        :return: The representation size of this encoder.
        """
        raise NotImplementedError()

    def get_encoded_seq_len(self, seq_len: int) -> int:
        """
        :return: The size of the encoded sequence.
        """
        return seq_len

    def get_max_seq_len(self) -> Optional[int]:
        """
        :return: The maximum length supported by the encoder if such a restriction exists.
        """
        return None

class ConvertLayout(Encoder):
    """
    Converts batch major data to time major by swapping the first dimension and setting the __layout__ attribute.

    :param target_layout: The target layout to convert to (C.BATCH_MAJOR or C.TIMEMAJOR).
    :param num_hidden: The number of hidden units of the previous encoder.
    :param dtype: Data type.
    """

    def __init__(self, target_layout: str, num_hidden: int, dtype: str = C.DTYPE_FP32) -> None:
        assert target_layout == C.BATCH_MAJOR or target_layout == C.TIME_MAJOR
        super().__init__(dtype)
        self.num_hidden = num_hidden
        self.target_layout = target_layout

    def encode(self,
               data: mx.sym.Symbol,
               data_length: Optional[mx.sym.Symbol],
               seq_len: int) -> Tuple[mx.sym.Symbol, mx.sym.Symbol, int]:
        """
        Encodes data given sequence lengths of individual examples and maximum sequence length.

        :param data: Input data.
        :param data_length: Vector with sequence lengths.
        :param seq_len: Maximum sequence length.
        :return: Encoded versions of input data (data, data_length, seq_len).
        """
        with mx.AttrScope(__layout__=self.target_layout):
            return mx.sym.swapaxes(data=data, dim1=0, dim2=1), data_length, seq_len

    def get_num_hidden(self) -> int:
        return self.num_hidden

class ReverseSequence(Encoder):
    """
    Reverses the input sequence. Requires time-major layout.

    :param dtype: Data type.
    """

    def __init__(self, num_hidden: int, dtype: str = C.DTYPE_FP32) -> None:
        super().__init__(dtype)
        self.num_hidden = num_hidden

    def encode(self,
               data: mx.sym.Symbol,
               data_length: mx.sym.Symbol,
               seq_len: int) -> Tuple[mx.sym.Symbol, mx.sym.Symbol, int]:
        data = mx.sym.SequenceReverse(data=data, sequence_length=data_length, use_sequence_length=True)
        return data, data_length, seq_len

    def get_num_hidden(self):
        return self.num_hidden

class FactorConfig(config.Config):

    def __init__(self, vocab_size: int, num_embed: int) -> None:
        super().__init__()
        self.vocab_size = vocab_size
        self.num_embed = num_embed

class EmbeddingConfig(config.Config):

    def __init__(self,
                 vocab_size: int,
                 num_embed: int,
                 dropout: float,
                 factor_configs: Optional[List[FactorConfig]] = None,
                 dtype: str = C.DTYPE_FP32) -> None:
        super().__init__()
        self.vocab_size = vocab_size
        self.num_embed = num_embed
        self.dropout = dropout
        self.factor_configs = factor_configs
        self.num_factors = 1
        if self.factor_configs is not None:
            self.num_factors += len(self.factor_configs)
        self.dtype = dtype

class Embedding(Encoder):
    """
    Thin wrapper around MXNet's Embedding symbol. Works with both time- and batch-major data layouts.

    :param config: Embedding config.
    :param prefix: Name prefix for symbols of this encoder.
    :param embed_weight: Optionally use an existing embedding matrix instead of creating a new one.
    :param is_source: Whether this is the source embedding instance. Default: False.
    """

    def __init__(self,
                 config: EmbeddingConfig,
                 prefix: str,
                 embed_weight: Optional[mx.sym.Symbol] = None,
                 is_source: bool = False) -> None:
        super().__init__(config.dtype)
        self.config = config
        self.prefix = prefix
        self.embed_weight = embed_weight
        self.is_source = is_source

        if self.embed_weight is None:
            self.embed_weight = mx.sym.Variable(prefix + "weight",
                                                shape=(self.config.vocab_size, self.config.num_embed))

        self.embed_factor_weights = []  # type: List[mx.sym.Symbol]
        if self.config.factor_configs is not None:
            # Factors weights aren't shared so they're not passed in and we create them here.
            for i, fc in enumerate(self.config.factor_configs):
                self.embed_factor_weights.append(mx.sym.Variable(prefix + "factor%d_weight" % i,
                                                                 shape=(fc.vocab_size, fc.num_embed)))

    def encode(self,
               data: mx.sym.Symbol,
               data_length: Optional[mx.sym.Symbol],
               seq_len: int) -> Tuple[mx.sym.Symbol, mx.sym.Symbol, int]:
        """
        Encodes data given sequence lengths of individual examples and maximum sequence length.

        :param data: Input data.
        :param data_length: Vector with sequence lengths.
        :param seq_len: Maximum sequence length.
        :return: Encoded versions of input data (data, data_length, seq_len).
        """
        factor_embeddings = []  # type: List[mx.sym.Symbol]
        if self.is_source:
            data, *data_factors = mx.sym.split(data=data,
                                               num_outputs=self.config.num_factors,
                                               axis=2,
                                               squeeze_axis=True, name=self.prefix + "factor_split")

            if self.config.factor_configs is not None:
                for i, (factor_data, factor_config, factor_weight) in enumerate(zip(data_factors,
                                                                                self.config.factor_configs,
                                                                                self.embed_factor_weights)):
                    factor_embeddings.append(mx.sym.Embedding(data=factor_data,
                                                              input_dim=factor_config.vocab_size,
                                                              weight=factor_weight,
                                                              output_dim=factor_config.num_embed,
                                                              name=self.prefix + "factor%d_embed" % i))

        embedding = mx.sym.Embedding(data=data,
                                     input_dim=self.config.vocab_size,
                                     weight=self.embed_weight,
                                     output_dim=self.config.num_embed,
                                     name=self.prefix + "embed")

        if self.config.factor_configs is not None:
            embedding = mx.sym.concat(embedding, *factor_embeddings, dim=2, name=self.prefix + "embed_plus_factors")

        if self.config.dropout > 0:
            embedding = mx.sym.Dropout(data=embedding, p=self.config.dropout, name="source_embed_dropout")

        return embedding, data_length, seq_len

    def get_num_hidden(self) -> int:
        """
        Return the representation size of this encoder.
        """
        return self.config.num_embed

class PassThroughEmbeddingConfig(EmbeddingConfig):

    def __init__(self) -> None:
        super().__init__(vocab_size=0, num_embed=0, dropout=0.0, factor_configs=None)

class PassThroughEmbedding(Encoder):
    """
    This is an embedding which passes through an input symbol without doing any operation.

    :param config: PassThroughEmbeddingConfig config.
    """

    def __init__(self,
                 config: PassThroughEmbeddingConfig) -> None:
        super().__init__('float32')
        self.config = config

    def encode(self,
               data: mx.sym.Symbol,
               data_length: Optional[mx.sym.Symbol],
               seq_len: int = 0) -> Tuple[mx.sym.Symbol, mx.sym.Symbol, int]:
        """
        Encodes data given sequence lengths of individual examples and maximum sequence length.

        :param data: Input data.
        :param data_length: Vector with sequence lengths.
        :return: Encoded versions of input data (data, data_length, seq_len).
        """
        return data, data_length, seq_len

    def get_num_hidden(self) -> int:
        """
        Return the representation size of this encoder.
        """
        return 0

class PositionalEncoder(Encoder):
    @abstractmethod
    def encode_positions(self,
                         positions: mx.sym.Symbol,
                         data: mx.sym.Symbol) -> mx.sym.Symbol:
        """
        Add positional encodings to the data using the provided positions.
        :param positions: (batch_size,)
        :param data: (batch_size, num_embed)
        :return: (batch_size, num_embed)
        """
        pass

class AddSinCosPositionalEmbeddings(PositionalEncoder):
    """
    Takes an encoded sequence and adds fixed positional embeddings as in Vaswani et al, 2017 to it.

    :param num_embed: Embedding size.
    :param prefix: Name prefix for symbols of this encoder.
    :param scale_up_input: If True, scales input data up by num_embed ** 0.5.
    :param scale_down_positions: If True, scales positional embeddings down by num_embed ** -0.5.
    :param dtype: Data type.
    """

    def __init__(self,
                 num_embed: int,
                 prefix: str,
                 scale_up_input: bool,
                 scale_down_positions: bool,
                 dtype: str = C.DTYPE_FP32) -> None:
        utils.check_condition(num_embed % 2 == 0, "Positional embeddings require an even embedding size it "
                                                  "is however %d." % num_embed)
        super().__init__(dtype)
        self.scale_up_input = scale_up_input
        self.scale_down_positions = scale_down_positions
        self.num_embed = num_embed
        self.prefix = prefix

    def encode(self,
               data: mx.sym.Symbol,
               data_length: Optional[mx.sym.Symbol],
               seq_len: int) -> Tuple[mx.sym.Symbol, mx.sym.Symbol, int]:
        """
        :param data: (batch_size, source_seq_len, num_embed)
        :param data_length: (batch_size,)
        :param seq_len: sequence length.
        :return: (batch_size, source_seq_len, num_embed)
        """
        # add positional embeddings to data
        if self.scale_up_input:
            data = data * (self.num_embed ** 0.5)

        positions = mx.sym.BlockGrad(mx.symbol.Custom(length=seq_len,
                                                      depth=self.num_embed,
                                                      name="%spositional_encodings" % self.prefix,
                                                      op_type='positional_encodings'))

        if self.scale_down_positions:
            positions = positions * (self.num_embed ** -0.5)

        embedding = mx.sym.broadcast_add(data, positions)
        return embedding, data_length, seq_len

    def encode_positions(self,
                         positions: mx.sym.Symbol,
                         data: mx.sym.Symbol) -> mx.sym.Symbol:
        """
        :param positions: (batch_size,)
        :param data: (batch_size, num_embed)
        :return: (batch_size, num_embed)
        """
        # (batch_size, 1)
        positions = mx.sym.expand_dims(positions, axis=1)
        # (num_embed,)
        channels = mx.sym.arange(0, self.num_embed // 2)
        # (1, num_embed,)
        scaling = mx.sym.expand_dims(1. / mx.sym.pow(10000, (2 * channels) / self.num_embed), axis=0)

        # (batch_size, num_embed/2)
        scaled_positions = mx.sym.dot(positions, scaling)

        sin = mx.sym.sin(scaled_positions)
        cos = mx.sym.cos(scaled_positions)

        # (batch_size, num_embed)
        pos_embedding = mx.sym.concat(sin, cos, dim=1)

        if self.scale_up_input:
            data = data * (self.num_embed ** 0.5)

        if self.scale_down_positions:
            pos_embedding = pos_embedding * (self.num_embed ** -0.5)

        return mx.sym.broadcast_add(data, pos_embedding, name="%s_add" % self.prefix)

    def get_num_hidden(self) -> int:
        return self.num_embed

class AddLearnedPositionalEmbeddings(PositionalEncoder):
    """
    Takes an encoded sequence and adds positional embeddings to it, which are learned jointly. Note that this will
    limited the maximum sentence length during decoding.

    :param num_embed: Embedding size.
    :param max_seq_len: Maximum sequence length.
    :param prefix: Name prefix for symbols of this encoder.
    :param embed_weight: Optionally use an existing embedding matrix instead of creating a new one.
    :param dtype: Data type.
    """

    def __init__(self,
                 num_embed: int,
                 max_seq_len: int,
                 prefix: str,
                 embed_weight: Optional[mx.sym.Symbol] = None,
                 dtype: str = C.DTYPE_FP32) -> None:
        super().__init__(dtype)
        self.num_embed = num_embed
        self.max_seq_len = max_seq_len
        self.prefix = prefix
        if embed_weight is not None:
            self.embed_weight = embed_weight
        else:
            self.embed_weight = mx.sym.Variable(prefix + "weight")

    def encode(self,
               data: mx.sym.Symbol,
               data_length: Optional[mx.sym.Symbol],
               seq_len: int) -> Tuple[mx.sym.Symbol, mx.sym.Symbol, int]:
        """
        :param data: (batch_size, source_seq_len, num_embed)
        :param data_length: (batch_size,)
        :param seq_len: sequence length.
        :return: (batch_size, source_seq_len, num_embed)
        """

        # (1, source_seq_len)
        positions = mx.sym.expand_dims(data=mx.sym.arange(start=0, stop=seq_len, step=1), axis=0)

        # (1, source_seq_len, num_embed)
        pos_embedding = mx.sym.Embedding(data=positions,
                                         input_dim=self.max_seq_len,
                                         weight=self.embed_weight,
                                         output_dim=self.num_embed,
                                         name=self.prefix + "pos_embed")
        return mx.sym.broadcast_add(data, pos_embedding, name="%s_add" % self.prefix), data_length, seq_len

    def encode_positions(self,
                         positions: mx.sym.Symbol,
                         data: mx.sym.Symbol) -> mx.sym.Symbol:
        """
        :param positions: (batch_size,)
        :param data: (batch_size, num_embed)
        :return: (batch_size, num_embed)
        """

        # (batch_size, source_seq_len, num_embed)
        pos_embedding = mx.sym.Embedding(data=positions,
                                         input_dim=self.max_seq_len,
                                         weight=self.embed_weight,
                                         output_dim=self.num_embed,
                                         name=self.prefix + "pos_embed")
        return mx.sym.broadcast_add(data, pos_embedding, name="%s_add" % self.prefix)

    def get_num_hidden(self) -> int:
        return self.num_embed

    def get_max_seq_len(self) -> Optional[int]:
        # we can only support sentences as long as the maximum length during training.
        return self.max_seq_len

class NoOpPositionalEmbeddings(PositionalEncoder):
    """
    Simple NoOp pos embedding. It does not modify the data, but avoids lots of if statements.

    :param dtype: Data type.
    """

    def __init__(self, num_embed, dtype: str = C.DTYPE_FP32) -> None:
        super().__init__(dtype)
        self.num_embed = num_embed

    def encode(self,
               data: mx.sym.Symbol,
               data_length: Optional[mx.sym.Symbol],
               seq_len: int) -> Tuple[mx.sym.Symbol, mx.sym.Symbol, int]:
        return data, data_length, seq_len

    def encode_positions(self,
                         positions: mx.sym.Symbol,
                         data: mx.sym.Symbol) -> mx.sym.Symbol:
        return data

    def get_num_hidden(self) -> int:
        return self.num_embed

def _get_positional_embedding_params(positional_embedding_type: str,
                                     num_embed: int,
                                     max_seq_len: int,
                                     fixed_pos_embed_scale_up_input: bool = False,
                                     fixed_pos_embed_scale_down_positions: bool = False,
                                     prefix: str = '') -> Tuple[Callable, Dict]:
    if positional_embedding_type == C.FIXED_POSITIONAL_EMBEDDING:
        return AddSinCosPositionalEmbeddings, dict(num_embed=num_embed,
                                                   scale_up_input=fixed_pos_embed_scale_up_input,
                                                   scale_down_positions=fixed_pos_embed_scale_down_positions,
                                                   prefix=prefix)
    elif positional_embedding_type == C.LEARNED_POSITIONAL_EMBEDDING:
        return AddLearnedPositionalEmbeddings, dict(num_embed=num_embed,
                                                    max_seq_len=max_seq_len,
                                                    prefix=prefix)
    elif positional_embedding_type == C.NO_POSITIONAL_EMBEDDING:
        return NoOpPositionalEmbeddings, dict(num_embed=num_embed)
    else:
        raise ValueError("Unknown positional embedding type %s" % positional_embedding_type)

def get_positional_embedding(positional_embedding_type: str,
                             num_embed: int,
                             max_seq_len: int,
                             fixed_pos_embed_scale_up_input: bool = False,
                             fixed_pos_embed_scale_down_positions: bool = False,
                             prefix: str = '') -> PositionalEncoder:
    cls, encoder_params = _get_positional_embedding_params(positional_embedding_type,
                                                           num_embed,
                                                           max_seq_len,
                                                           fixed_pos_embed_scale_up_input,
                                                           fixed_pos_embed_scale_down_positions,
                                                           prefix)
    return cls(**encoder_params)

class EncoderSequence(Encoder):
    """
    A sequence of encoders is itself an encoder.

    :param encoders: List of encoders.
    :param dtype: Data type.
    """

    def __init__(self, encoders: List[Encoder], dtype: str = C.DTYPE_FP32) -> None:
        super().__init__(dtype)
        self.encoders = encoders

    def encode(self,
               data: mx.sym.Symbol,
               data_length: mx.sym.Symbol,
               seq_len: int) -> Tuple[mx.sym.Symbol, mx.sym.Symbol, int]:
        """
        Encodes data given sequence lengths of individual examples and maximum sequence length.

        :param data: Input data.
        :param data_length: Vector with sequence lengths.
        :param seq_len: Maximum sequence length.
        :return: Encoded versions of input data (data, data_length, seq_len).
        """
        for encoder in self.encoders:
            data, data_length, seq_len = encoder.encode(data, data_length, seq_len)
        return data, data_length, seq_len

    def get_num_hidden(self) -> int:
        """
        Return the representation size of this encoder.
        """
        return self.encoders[-1].get_num_hidden()

    def get_encoded_seq_len(self, seq_len: int) -> int:
        """
        Returns the size of the encoded sequence.
        """
        for encoder in self.encoders:
            seq_len = encoder.get_encoded_seq_len(seq_len)
        return seq_len

    def get_max_seq_len(self) -> Optional[int]:
        """
        :return: The maximum length supported by the encoder if such a restriction exists.
        """
        max_seq_len = min((encoder.get_max_seq_len()
                           for encoder in self.encoders if encoder.get_max_seq_len() is not None), default=None)
        return max_seq_len

    def append(self, cls, infer_hidden: bool = False, **kwargs) -> Encoder:
        """
        Extends sequence with new Encoder. 'dtype' gets passed into Encoder instance if not present in parameters
        and supported by specific Encoder type.

        :param cls: Encoder type.
        :param infer_hidden: If number of hidden should be inferred from previous encoder.
        :param kwargs: Named arbitrary parameters for Encoder.

        :return: Instance of Encoder.
        """
        params = dict(kwargs)
        if infer_hidden:
            params['num_hidden'] = self.get_num_hidden()

        sig_params = inspect.signature(cls.__init__).parameters
        if 'dtype' in sig_params and 'dtype' not in kwargs:
            params['dtype'] = self.dtype
        encoder = cls(**params)
        self.encoders.append(encoder)
        return encoder

class EmptyEncoder(Encoder):
    """
    This encoder ignores the input data and simply returns zero-filled states in the expected shape.
    :param config: configuration.
    """

    def __init__(self,
                 config: EmptyEncoderConfig) -> None:
        super().__init__(config.dtype)
        self.num_embed = config.num_embed
        self.num_hidden = config.num_hidden

    def encode(self,
               data: mx.sym.Symbol,
               data_length: Optional[mx.sym.Symbol],
               seq_len: int) -> Tuple[mx.sym.Symbol, mx.sym.Symbol, int]:
        """
        Encodes data given sequence lengths of individual examples and maximum sequence length.
        :param data: Input data.
        :param data_length: Vector with sequence lengths.
        :param seq_len: Maximum sequence length.
        :return: Expected number of empty states (zero-filled).
        """
        # outputs: (batch_size, seq_len, num_hidden)
        outputs = mx.sym.dot(data, mx.sym.zeros((self.num_embed, self.num_hidden)))
        return outputs, data_length, seq_len

    def get_num_hidden(self):
        """
        Return the representation size of this encoder.
        """
        return self.num_hidden

class RecurrentEncoder(Encoder):
    """
    Uni-directional (multi-layered) recurrent encoder.

    :param rnn_config: RNN configuration.
    :param prefix: Prefix for variable names.
    :param layout: Data layout.
    """

    def __init__(self,
                 rnn_config: rnn.RNNConfig,
                 prefix: str = C.STACKEDRNN_PREFIX,
                 layout: str = C.TIME_MAJOR) -> None:
        super().__init__(rnn_config.dtype)
        self.rnn_config = rnn_config
        self.layout = layout
        self.rnn = rnn.get_stacked_rnn(rnn_config, prefix)

    def encode(self,
               data: mx.sym.Symbol,
               data_length: Optional[mx.sym.Symbol],
               seq_len: int) -> Tuple[mx.sym.Symbol, mx.sym.Symbol, int]:
        """
        Encodes data given sequence lengths of individual examples and maximum sequence length.

        :param data: Input data.
        :param data_length: Vector with sequence lengths.
        :param seq_len: Maximum sequence length.
        :return: Encoded versions of input data (data, data_length, seq_len).
        """
        outputs, _ = self.rnn.unroll(seq_len, inputs=data, merge_outputs=True, layout=self.layout)

        return outputs, data_length, seq_len

    def get_rnn_cells(self):
        """
        Returns RNNCells used in this encoder.
        """
        return [self.rnn]

    def get_num_hidden(self):
        """
        Return the representation size of this encoder.
        """
        return self.rnn_config.num_hidden

class BiDirectionalRNNEncoder(Encoder):
    """
    An encoder that runs a forward and a reverse RNN over input data.
    States from both RNNs are concatenated together.

    :param rnn_config: RNN configuration.
    :param prefix: Prefix for variable names.
    :param layout: Data layout.
    :param encoder_class: Recurrent encoder class to use.
    """

    def __init__(self,
                 rnn_config: rnn.RNNConfig,
                 prefix=C.BIDIRECTIONALRNN_PREFIX,
                 layout=C.TIME_MAJOR,
                 encoder_class: Callable = RecurrentEncoder) -> None:
        utils.check_condition(rnn_config.num_hidden % 2 == 0,
                              "num_hidden must be a multiple of 2 for BiDirectionalRNNEncoders.")
        super().__init__(rnn_config.dtype)
        self.rnn_config = rnn_config
        self.internal_rnn_config = rnn_config.copy(num_hidden=rnn_config.num_hidden // 2)
        if layout[0] == 'N':
            logger.warning("Batch-major layout for encoder input. Consider using time-major layout for faster speed")

        # time-major layout as _encode needs to swap layout for SequenceReverse
        self.forward_rnn = encoder_class(rnn_config=self.internal_rnn_config,
                                         prefix=prefix + C.FORWARD_PREFIX,
                                         layout=C.TIME_MAJOR)
        self.reverse_rnn = encoder_class(rnn_config=self.internal_rnn_config,
                                         prefix=prefix + C.REVERSE_PREFIX,
                                         layout=C.TIME_MAJOR)
        self.layout = layout
        self.prefix = prefix

    def encode(self,
               data: mx.sym.Symbol,
               data_length: mx.sym.Symbol,
               seq_len: int) -> Tuple[mx.sym.Symbol, mx.sym.Symbol, int]:
        """
        Encodes data given sequence lengths of individual examples and maximum sequence length.

        :param data: Input data.
        :param data_length: Vector with sequence lengths.
        :param seq_len: Maximum sequence length.
        :return: Encoded versions of input data (data, data_length, seq_len).
        """
        if self.layout[0] == 'N':
            data = mx.sym.swapaxes(data=data, dim1=0, dim2=1)
        data = self._encode(data, data_length, seq_len)
        if self.layout[0] == 'N':
            data = mx.sym.swapaxes(data=data, dim1=0, dim2=1)
        return data, data_length, seq_len

    def _encode(self, data: mx.sym.Symbol, data_length: mx.sym.Symbol, seq_len: int) -> mx.sym.Symbol:
        """
        Bidirectionally encodes time-major data.
        """
        # (seq_len, batch_size, num_embed)
        data_reverse = mx.sym.SequenceReverse(data=data, sequence_length=data_length,
                                              use_sequence_length=True)
        # (seq_length, batch, cell_num_hidden)
        hidden_forward, _, _ = self.forward_rnn.encode(data, data_length, seq_len)
        # (seq_length, batch, cell_num_hidden)
        hidden_reverse, _, _ = self.reverse_rnn.encode(data_reverse, data_length, seq_len)
        # (seq_length, batch, cell_num_hidden)
        hidden_reverse = mx.sym.SequenceReverse(data=hidden_reverse, sequence_length=data_length,
                                                use_sequence_length=True)
        # (seq_length, batch, 2 * cell_num_hidden)
        hidden_concat = mx.sym.concat(hidden_forward, hidden_reverse, dim=2, name="%s_rnn" % self.prefix)

        return hidden_concat

    def get_num_hidden(self) -> int:
        """
        Return the representation size of this encoder.
        """
        return self.rnn_config.num_hidden

    def get_rnn_cells(self) -> List[mx.rnn.BaseRNNCell]:
        """
        Returns a list of RNNCells used by this encoder.
        """
        return self.forward_rnn.get_rnn_cells() + self.reverse_rnn.get_rnn_cells()

class ConvolutionalEncoder(Encoder):
    """
    Encoder that uses convolution instead of recurrent connections, similar to Gehring et al. 2017.

    :param config: Configuration for convolutional encoder.
    :param prefix: Name prefix for operations in this encoder.
    """

    def __init__(self,
                 config: ConvolutionalEncoderConfig,
                 prefix: str = C.CNN_ENCODER_PREFIX) -> None:
        super().__init__(config.dtype)
        self.config = config

        # initialize the weights of the linear transformation required for the residual connections
        self.i2h_weight = mx.sym.Variable('%si2h_weight' % prefix)

        # initialize the layers of blocks containing a convolution and a GLU, since
        # every layer is shared over all encode calls
        self.layers = [convolution.ConvolutionBlock(
            config.cnn_config,
            pad_type='centered',
            prefix="%s%d_" % (prefix, i)) for i in range(config.num_layers)]

    def encode(self,
               data: mx.sym.Symbol,
               data_length: mx.sym.Symbol,
               seq_len: int) -> Tuple[mx.sym.Symbol, mx.sym.Symbol, int]:
        """
        Encodes data with a stack of Convolution+GLU blocks given sequence lengths of individual examples
        and maximum sequence length.

        :param data: Input data. Shape: (batch_size, seq_len, input_num_hidden).
        :param data_length: Vector with sequence lengths.
        :param seq_len: Maximum sequence length.
        :return: Encoded version of the data.
        """
        # data: (batch_size, seq_len, num_hidden)
        data = mx.sym.FullyConnected(data=data,
                                     num_hidden=self.config.cnn_config.num_hidden,
                                     no_bias=True,
                                     flatten=False,
                                     weight=self.i2h_weight)

        # Multiple layers with residual connections:
        for layer in self.layers:
            data = data + layer(data, data_length, seq_len)
        return data, data_length, seq_len

    def get_num_hidden(self) -> int:
        return self.config.cnn_config.num_hidden

class TransformerEncoder(Encoder):
    """
    Non-recurrent encoder based on the transformer architecture in:

    Attention Is All You Need, Figure 1 (left)
    Vaswani et al. (https://arxiv.org/pdf/1706.03762.pdf).

    :param config: Configuration for transformer encoder.
    :param prefix: Name prefix for operations in this encoder.
    """

    def __init__(self,
                 config: transformer.TransformerConfig,
                 prefix: str = C.TRANSFORMER_ENCODER_PREFIX) -> None:
        super().__init__(config.dtype)
        self.config = config
        self.prefix = prefix
        self.layers = [transformer.TransformerEncoderBlock(
            config, prefix="%s%d_" % (prefix, i)) for i in range(config.num_layers)]
        self.final_process = transformer.TransformerProcessBlock(sequence=config.preprocess_sequence,
                                                                 dropout=config.dropout_prepost,
                                                                 prefix="%sfinal_process_" % prefix)

    def encode(self,
               data: mx.sym.Symbol,
               data_length: mx.sym.Symbol,
               seq_len: int) -> Tuple[mx.sym.Symbol, mx.sym.Symbol, int]:
        """
        Encodes data given sequence lengths of individual examples and maximum sequence length.

        :param data: Input data.
        :param data_length: Vector with sequence lengths.
        :param seq_len: Maximum sequence length.
        :return: Encoded versions of input data data, data_length, seq_len.
        """
        data = utils.cast_conditionally(data, self.dtype)
        if self.config.dropout_prepost > 0.0:
            data = mx.sym.Dropout(data=data, p=self.config.dropout_prepost)

        # (batch_size * heads, 1, max_length)
        bias = mx.sym.expand_dims(transformer.get_variable_length_bias(lengths=data_length,
                                                                       max_length=seq_len,
                                                                       num_heads=self.config.attention_heads,
                                                                       fold_heads=True,
                                                                       name="%sbias" % self.prefix), axis=1)
        bias = utils.cast_conditionally(bias, self.dtype)
        for i, layer in enumerate(self.layers):
            # (batch_size, seq_len, config.model_size)
            data = layer(data, bias)
        data = self.final_process(data=data, prev=None)
        data = utils.uncast_conditionally(data, self.dtype)
        return data, data_length, seq_len

    def get_num_hidden(self) -> int:
        """
        Return the representation size of this encoder.
        """
        return self.config.model_size

class ConvolutionalEmbeddingConfig(config.Config):
    """
    Convolutional embedding encoder configuration.

    :param num_embed: Input embedding size.
    :param output_dim: Output segment embedding size.
    :param max_filter_width: Maximum filter width for convolutions.
    :param num_filters: Number of filters of each width.
    :param pool_stride: Stride for pooling layer after convolutions.
    :param num_highway_layers: Number of highway layers for segment embeddings.
    :param dropout: Dropout probability.
    :param add_positional_encoding: Dropout probability.
    :param dtype: Data type.
    """

    def __init__(self,
                 num_embed: int,
                 output_dim: int = None,
                 max_filter_width: int = 8,
                 num_filters: Tuple[int, ...] = (200, 200, 250, 250, 300, 300, 300, 300),
                 pool_stride: int = 5,
                 num_highway_layers: int = 4,
                 dropout: float = 0.0,
                 add_positional_encoding: bool = False,
                 dtype: str = C.DTYPE_FP32) -> None:
        super().__init__()
        self.num_embed = num_embed
        self.output_dim = output_dim
        self.max_filter_width = max_filter_width
        self.num_filters = num_filters
        self.pool_stride = pool_stride
        self.num_highway_layers = num_highway_layers
        self.dropout = dropout
        self.add_positional_encoding = add_positional_encoding
        if self.output_dim is None:
            self.output_dim = sum(self.num_filters)
        self.dtype = dtype

class ConvolutionalEmbeddingEncoder(Encoder):
    """
    An encoder developed to map a sequence of character embeddings to a shorter sequence of segment
    embeddings using convolutional, pooling, and highway layers.  More generally, it maps a sequence
    of input embeddings to a sequence of span embeddings.

    * "Fully Character-Level Neural Machine Translation without Explicit Segmentation"
      Jason Lee; Kyunghyun Cho; Thomas Hofmann (https://arxiv.org/pdf/1610.03017.pdf)

    :param config: Convolutional embedding config.
    :param prefix: Name prefix for symbols of this encoder.
    """

    def __init__(self,
                 config: ConvolutionalEmbeddingConfig,
                 prefix: str = C.CHAR_SEQ_ENCODER_PREFIX) -> None:
        utils.check_condition(len(config.num_filters) == config.max_filter_width,
                              "num_filters must have max_filter_width elements.")
        super().__init__(config.dtype)
        self.num_embed = config.num_embed
        self.output_dim = config.output_dim
        self.max_filter_width = config.max_filter_width
        self.num_filters = config.num_filters[:]
        self.pool_stride = config.pool_stride
        self.num_highway_layers = config.num_highway_layers
        self.prefix = prefix
        self.dropout = config.dropout
        self.add_positional_encoding = config.add_positional_encoding

        self.conv_weight = {filter_width: mx.sym.Variable("%s%s%d%s" % (self.prefix, "conv_", filter_width, "_weight"))
                            for filter_width in range(1, self.max_filter_width + 1)}
        self.conv_bias = {filter_width: mx.sym.Variable("%s%s%d%s" % (self.prefix, "conv_", filter_width, "_bias"))
                          for filter_width in range(1, self.max_filter_width + 1)}

        self.project_weight = mx.sym.Variable(self.prefix + "project_weight")
        self.project_bias = mx.sym.Variable(self.prefix + "project_bias")

        self.gate_weight = [mx.sym.Variable("%s%s%d%s" % (self.prefix, "gate_", i, "_weight"))
                            for i in range(self.num_highway_layers)]
        self.gate_bias = [mx.sym.Variable("%s%s%d%s" % (self.prefix, "gate_", i, "_bias"))
                          for i in range(self.num_highway_layers)]

        self.transform_weight = [mx.sym.Variable("%s%s%d%s" % (self.prefix, "transform_", i, "_weight"))
                                 for i in range(self.num_highway_layers)]
        self.transform_bias = [mx.sym.Variable("%s%s%d%s" % (self.prefix, "transform_", i, "_bias"))
                               for i in range(self.num_highway_layers)]

    def encode(self,
               data: mx.sym.Symbol,
               data_length: mx.sym.Symbol,
               seq_len: int) -> Tuple[mx.sym.Symbol, mx.sym.Symbol, int]:
        """
        Encodes data given sequence lengths of individual examples and maximum sequence length.

        :param data: Input data.
        :param data_length: Vector with sequence lengths.
        :param seq_len: Maximum sequence length.
        :return: Encoded versions of input data data, data_length, seq_len.
        """
        total_num_filters = sum(self.num_filters)
        encoded_seq_len = self.get_encoded_seq_len(seq_len)

        # (batch_size, channel=1, seq_len, num_embed)
        data = mx.sym.Reshape(data=data, shape=(-1, 1, seq_len, self.num_embed))

        # Convolution filters of width 1..N
        conv_outputs = []
        for filter_width, num_filter in enumerate(self.num_filters, 1):
            # "half" padding: output length == input length
            pad_before = ceil((filter_width - 1) / 2)
            pad_after = floor((filter_width - 1) / 2)
            # (batch_size, channel=1, seq_len + (filter_width - 1), num_embed)
            padded = mx.sym.pad(data=data,
                                mode="constant",
                                constant_value=0,
                                pad_width=(0, 0, 0, 0, pad_before, pad_after, 0, 0))
            # (batch_size, num_filter, seq_len, num_scores=1)
            conv = mx.sym.Convolution(data=padded,
                                      # cudnn_tune="off",
                                      kernel=(filter_width, self.num_embed),
                                      num_filter=num_filter,
                                      weight=self.conv_weight[filter_width],
                                      bias=self.conv_bias[filter_width])
            conv = mx.sym.Activation(data=conv, act_type="relu")
            conv_outputs.append(conv)
        # (batch_size, total_num_filters, seq_len, num_scores=1)
        conv_concat = mx.sym.concat(*conv_outputs, dim=1)

        # Max pooling with stride
        uncovered = seq_len % self.pool_stride
        if uncovered > 0:
            pad_after = self.pool_stride - uncovered
            # (batch_size, total_num_filters, seq_len + pad_to_final_stride, num_scores=1)
            conv_concat = mx.sym.pad(data=conv_concat,
                                     mode="constant",
                                     constant_value=0,
                                     pad_width=(0, 0, 0, 0, 0, pad_after, 0, 0))
        # (batch_size, total_num_filters, seq_len/stride, num_scores=1)
        pool = mx.sym.Pooling(data=conv_concat,
                              pool_type="max",
                              kernel=(self.pool_stride, 1),
                              stride=(self.pool_stride, 1))
        # (batch_size, total_num_filters, seq_len/stride)
        pool = mx.sym.reshape(data=pool,
                              shape=(-1, total_num_filters, encoded_seq_len))
        # (batch_size, seq_len/stride, total_num_filters)
        pool = mx.sym.swapaxes(data=pool, dim1=1, dim2=2)
        if self.dropout > 0:
            pool = mx.sym.Dropout(data=pool, p=self.dropout)

        # Raw segment embeddings reshaped for highway network
        # (batch_size * seq_len/stride, total_num_filters)
        seg_embedding = mx.sym.Reshape(data=pool, shape=(-3, total_num_filters))

        # Projection layer if requested output dimension is different from total number of filters
        # (TransformerEncoder compatibility, not in original paper)
        if self.output_dim != total_num_filters:
            # (batch_size * seq_len/stride, outut_dim)
            seg_embedding = mx.sym.FullyConnected(data=seg_embedding,
                                                  num_hidden=self.output_dim,
                                                  weight=self.project_weight,
                                                  bias=self.project_bias)
            seg_embedding = mx.sym.Activation(data=seg_embedding, act_type="relu")
            if self.dropout > 0:
                seg_embedding = mx.sym.Dropout(data=seg_embedding, p=self.dropout)

        # Highway network
        for i in range(self.num_highway_layers):
            # Gate
            gate = mx.sym.FullyConnected(data=seg_embedding,
                                         num_hidden=self.output_dim,
                                         weight=self.gate_weight[i],
                                         bias=self.gate_bias[i])
            gate = mx.sym.Activation(data=gate, act_type="sigmoid")
            if self.dropout > 0:
                gate = mx.sym.Dropout(data=gate, p=self.dropout)
            # Transform
            transform = mx.sym.FullyConnected(data=seg_embedding,
                                              num_hidden=self.output_dim,
                                              weight=self.transform_weight[i],
                                              bias=self.transform_bias[i])
            transform = mx.sym.Activation(data=transform, act_type="relu")
            if self.dropout > 0:
                transform = mx.sym.Dropout(data=transform, p=self.dropout)
            # Connection
            seg_embedding = gate * transform + (1 - gate) * seg_embedding
        # (batch_size, seq_len/stride, output_dim) aka
        # (batch_size, encoded_seq_len, num_segment_embed)
        seg_embedding = mx.sym.Reshape(data=seg_embedding,
                                       shape=(-1, encoded_seq_len, self.output_dim))

        # Dropout on final segment embeddings
        if self.dropout > 0:
            seg_embedding = mx.sym.Dropout(data=seg_embedding, p=self.dropout)

        # Ceiling function isn't differentiable so this will throw errors if we
        # attempt to compute gradients.  Fortunately we aren't updating inputs
        # so we can just block the backward pass here.
        encoded_data_length = mx.sym.BlockGrad(mx.sym.ceil(data_length / self.pool_stride))

        return seg_embedding, encoded_data_length, encoded_seq_len

    def get_num_hidden(self) -> int:
        """
        Return the representation size of this encoder.
        """
        return self.output_dim

    def get_encoded_seq_len(self, seq_len: int) -> int:
        """
        Returns the size of the encoded sequence.
        """
        return int(ceil(seq_len / self.pool_stride))

EncoderConfig = Union[RecurrentEncoderConfig, transformer.TransformerConfig, ConvolutionalEncoderConfig,
                      EmptyEncoderConfig]
if ImageEncoderConfig is not None:
    EncoderConfig = Union[EncoderConfig, ImageEncoderConfig]  # type: ignore


text:
/*!
 * Start Bootstrap - Grayscale Bootstrap Theme (http://startbootstrap.com)
 * Code licensed under the Apache License v2.0.
 * For details, see http://www.apache.org/licenses/LICENSE-2.0.
 */

// jQuery to collapse the navbar on scroll
$(window).scroll(function() {
    if ($(".navbar").offset().top > 50) {
        $(".navbar-fixed-top").addClass("top-nav-collapse");
    } else {
        $(".navbar-fixed-top").removeClass("top-nav-collapse");
    }
});

$(document).ready(function() {
    //containerexp animatie
    $('.containerexp').mouseenter(function() {
        $(this).animate({"margin-top":"-0.4em"}, 100);
        //$(this).find('.cont').animate({"margin-top":"-0.1em"}, 100);
        $(this).find('.glyphicon').animate({"margin-top":"-0.02em"}, 100);
        $(this).css('background' , '#fff');
        $(this).find('h3').css('color' , '#1DE9B6');
        $(this).find('p').css('color' , '#656565');
        $(this).find('p').css('display' , 'block');
        $(this).find('.glyphicon').css('color' , '#fff');

        //$(this).mouseleave(function() {
        //    $(this).animate({"margin-top":"2.5em"}, 100)});
    });

    // jQuery for page scrolling feature - requires jQuery Easing plugin
    $('a.page-scroll').bind('click', function(event) {
        var $anchor = $(this);
        $('html, body').stop().animate({
            scrollTop: $($anchor.attr('href')).offset().top
        }, 1500, 'easeInOutExpo');
        event.preventDefault();
    });
});

// Closes the Responsive Menu on Menu Item Click
$('.navbar-collapse ul li a').click(function() {
    $('.navbar-toggle:visible').click();
});


text:
// -----------------------------------------------------------------------
//  <copyright file="EventBusBuilder.cs" company="OSharp开源团队">
//      Copyright (c) 2014-2017 OSharp. All rights reserved.
//  </copyright>
//  <site>http://www.osharp.org</site>
//  <last-editor>郭明锋</last-editor>
//  <last-date>2017-09-18 18:29</last-date>
// -----------------------------------------------------------------------

using System;

namespace OSharp.EventBuses.Internal
{
    /// <summary>
    /// EventBus初始化
    /// </summary>
    internal class EventBusBuilder : IEventBusBuilder
    {
        private readonly IEventHandlerTypeFinder _typeFinder;
        private readonly IEventBus _eventBus;

        /// <summary>
        /// 初始化一个<see cref="EventBusBuilder"/>类型的新实例
        /// </summary>
        public EventBusBuilder(IEventHandlerTypeFinder typeFinder, IEventBus eventBus)
        {
            _typeFinder = typeFinder;
            _eventBus = eventBus;
        }

        /// <summary>
        /// 初始化EventBus
        /// </summary>
        public void Build()
        {
            Type[] types = _typeFinder.FindAll(true);
            if (types.Length == 0)
            {
                return;
            }
            _eventBus.SubscribeAll(types);
        }
    }
}