gt:                 if (flag1 && flag3 && !flag && !flag2)
context: package net.minecraft.block;
  
  import com.google.common.collect.Lists;
  import java.util.List;
  import javax.annotation.Nullable;
  import net.minecraft.block.material.EnumPushReaction;
  import net.minecraft.block.material.Material;
  import net.minecraft.block.properties.IProperty;
  import net.minecraft.block.state.IBlockState;
  import net.minecraft.creativetab.CreativeTabs;
  import net.minecraft.init.Blocks;
  import net.minecraft.util.BlockRenderLayer;
  import net.minecraft.util.EnumFacing;
  import net.minecraft.util.IStringSerializable;
  import net.minecraft.util.math.AxisAlignedBB;
  import net.minecraft.util.math.BlockPos;
  import net.minecraft.world.IBlockAccess;
  import net.minecraft.world.World;
  import net.minecraftforge.fml.relauncher.Side;
  import net.minecraftforge.fml.relauncher.SideOnly;
  
  public abstract class BlockRailBase extends Block
  {
      protected static final AxisAlignedBB FLAT_AABB = new AxisAlignedBB(0.0D, 0.0D, 0.0D, 1.0D, 0.125D, 1.0D);
      protected static final AxisAlignedBB ASCENDING_AABB = new AxisAlignedBB(0.0D, 0.0D, 0.0D, 1.0D, 0.15625D, 1.0D);
      protected final boolean isPowered;
  
      public static boolean isRailBlock(World worldIn, BlockPos pos)
      {
          return isRailBlock(worldIn.getBlockState(pos));
      }
  
      public static boolean isRailBlock(IBlockState state)
      {
          Block block = state.getBlock();
          return block instanceof BlockRailBase;
      }
  
      protected BlockRailBase(boolean isPowered)
      {
          super(Material.CIRCUITS);
          this.isPowered = isPowered;
          this.setCreativeTab(CreativeTabs.TRANSPORTATION);
      }
  
      @Nullable
      public AxisAlignedBB getCollisionBoundingBox(IBlockState blockState, World worldIn, BlockPos pos)
      {
          return NULL_AABB;
      }
  
      /**
       * Used to determine ambient occlusion and culling when rebuilding chunks for render
       */
      public boolean isOpaqueCube(IBlockState state)
      {
          return false;
      }
  
      public AxisAlignedBB getBoundingBox(IBlockState state, IBlockAccess source, BlockPos pos)
      {
          BlockRailBase.EnumRailDirection blockrailbase$enumraildirection = state.getBlock() == this ? (BlockRailBase.EnumRailDirection)state.getValue(this.getShapeProperty()) : null;
          return blockrailbase$enumraildirection != null && blockrailbase$enumraildirection.isAscending() ? ASCENDING_AABB : FLAT_AABB;
      }
  
      public boolean isFullCube(IBlockState state)
      {
          return false;
      }
  
      public boolean canPlaceBlockAt(World worldIn, BlockPos pos)
      {
          return worldIn.getBlockState(pos.down()).isSideSolid(worldIn, pos, EnumFacing.UP);
      }
  
      public void onBlockAdded(World worldIn, BlockPos pos, IBlockState state)
      {
          if (!worldIn.isRemote)
          {
              state = this.updateDir(worldIn, pos, state, true);
  
              if (this.isPowered)
              {
                  state.neighborChanged(worldIn, pos, this);
              }
          }
      }
  
      /**
       * Called when a neighboring block was changed and marks that this state should perform any checks during a neighbor
       * change. Cases may include when redstone power is updated, cactus blocks popping off due to a neighboring solid
       * block, etc.
       */
      public void neighborChanged(IBlockState state, World worldIn, BlockPos pos, Block blockIn)
      {
          if (!worldIn.isRemote)
          {
              BlockRailBase.EnumRailDirection blockrailbase$enumraildirection = (BlockRailBase.EnumRailDirection)state.getValue(this.getShapeProperty());
              boolean flag = false;
  
              if (!worldIn.getBlockState(pos.down()).isSideSolid(worldIn, pos.down(), EnumFacing.UP))
              {
                  flag = true;
              }
  
              if (blockrailbase$enumraildirection == BlockRailBase.EnumRailDirection.ASCENDING_EAST && !worldIn.getBlockState(pos.east()).isSideSolid(worldIn, pos.east(), EnumFacing.UP))
              {
                  flag = true;
              }
              else if (blockrailbase$enumraildirection == BlockRailBase.EnumRailDirection.ASCENDING_WEST && !worldIn.getBlockState(pos.west()).isSideSolid(worldIn, pos.west(), EnumFacing.UP))
              {
                  flag = true;
              }
              else if (blockrailbase$enumraildirection == BlockRailBase.EnumRailDirection.ASCENDING_NORTH && !worldIn.getBlockState(pos.north()).isSideSolid(worldIn, pos.north(), EnumFacing.UP))
              {
                  flag = true;
              }
              else if (blockrailbase$enumraildirection == BlockRailBase.EnumRailDirection.ASCENDING_SOUTH && !worldIn.getBlockState(pos.south()).isSideSolid(worldIn, pos.south(), EnumFacing.UP))
              {
                  flag = true;
              }
  
              if (flag && !worldIn.isAirBlock(pos))
              {
                  this.dropBlockAsItem(worldIn, pos, state, 0);
                  worldIn.setBlockToAir(pos);
              }
              else
              {
                  this.updateState(state, worldIn, pos, blockIn);
              }
          }
      }
  
      protected void updateState(IBlockState p_189541_1_, World p_189541_2_, BlockPos p_189541_3_, Block p_189541_4_)
      {
      }
  
      protected IBlockState updateDir(World worldIn, BlockPos pos, IBlockState state, boolean p_176564_4_)
      {
          return worldIn.isRemote ? state : (new BlockRailBase.Rail(worldIn, pos, state)).place(worldIn.isBlockPowered(pos), p_176564_4_).getBlockState();
      }
  
      public EnumPushReaction getMobilityFlag(IBlockState state)
      {
          return EnumPushReaction.NORMAL;
      }
  
      @SideOnly(Side.CLIENT)
      public BlockRenderLayer getBlockLayer()
      {
          return BlockRenderLayer.CUTOUT;
      }
  
      public void breakBlock(World worldIn, BlockPos pos, IBlockState state)
      {
          super.breakBlock(worldIn, pos, state);
  
          if (((BlockRailBase.EnumRailDirection)state.getValue(this.getShapeProperty())).isAscending())
          {
              worldIn.notifyNeighborsOfStateChange(pos.up(), this);
          }
  
          if (this.isPowered)
          {
              worldIn.notifyNeighborsOfStateChange(pos, this);
              worldIn.notifyNeighborsOfStateChange(pos.down(), this);
          }
      }
  
      public abstract IProperty<BlockRailBase.EnumRailDirection> getShapeProperty();
  
      /* ======================================== FORGE START =====================================*/
      /**
       * Return true if the rail can make corners.
       * Used by placement logic.
       * @param world The world.
       * @param pos Block's position in world
       * @return True if the rail can make corners.
       */
      public boolean isFlexibleRail(IBlockAccess world, BlockPos pos)
      {
          return !this.isPowered;
      }
  
      /**
       * Returns true if the rail can make up and down slopes.
       * Used by placement logic.
       * @param world The world.
       * @param pos Block's position in world
       * @return True if the rail can make slopes.
       */
      public boolean canMakeSlopes(IBlockAccess world, BlockPos pos)
      {
          return true;
      }
  
      /**
       * Return the rail's direction.
       * Can be used to make the cart think the rail is a different shape,
       * for example when making diamond junctions or switches.
       * The cart parameter will often be null unless it it called from EntityMinecart.
       *
       * @param world The world.
       * @param pos Block's position in world
       * @param state The BlockState
       * @param cart The cart asking for the metadata, null if it is not called by EntityMinecart.
       * @return The direction.
       */
      public EnumRailDirection getRailDirection(IBlockAccess world, BlockPos pos, IBlockState state, @javax.annotation.Nullable net.minecraft.entity.item.EntityMinecart cart)
      {
          return state.getValue(getShapeProperty());
      }
  
      /**
       * Returns the max speed of the rail at the specified position.
       * @param world The world.
       * @param cart The cart on the rail, may be null.
       * @param pos Block's position in world
       * @return The max speed of the current rail.
       */
      public float getRailMaxSpeed(World world, net.minecraft.entity.item.EntityMinecart cart, BlockPos pos)
      {
          return 0.4f;
      }
  
      /**
       * This function is called by any minecart that passes over this rail.
       * It is called once per update tick that the minecart is on the rail.
       * @param world The world.
       * @param cart The cart on the rail.
       * @param pos Block's position in world
       */
      public void onMinecartPass(World world, net.minecraft.entity.item.EntityMinecart cart, BlockPos pos)
      {
      }
  
      /**
       * Rotate the block. For vanilla blocks this rotates around the axis passed in (generally, it should be the "face" that was hit).
       * Note: for mod blocks, this is up to the block and modder to decide. It is not mandated that it be a rotation around the
       * face, but could be a rotation to orient *to* that face, or a visiting of possible rotations.
       * The method should return true if the rotation was successful though.
       *
       * @param world The world
       * @param pos Block position in world
       * @param axis The axis to rotate around
       * @return True if the rotation was successful, False if the rotation failed, or is not possible
       */
      public boolean rotateBlock(World world, BlockPos pos, EnumFacing axis)
      {
          IBlockState state = world.getBlockState(pos);
          for (IProperty prop : state.getProperties().keySet())
          {
              if (prop.getName().equals("shape"))
              {
                  world.setBlockState(pos, state.cycleProperty(prop));
                  return true;
              }
          }
          return false;
      }
  
      /* ======================================== FORGE END =====================================*/
  
      public static enum EnumRailDirection implements IStringSerializable
      {
          NORTH_SOUTH(0, "north_south"),
          EAST_WEST(1, "east_west"),
          ASCENDING_EAST(2, "ascending_east"),
          ASCENDING_WEST(3, "ascending_west"),
          ASCENDING_NORTH(4, "ascending_north"),
          ASCENDING_SOUTH(5, "ascending_south"),
          SOUTH_EAST(6, "south_east"),
          SOUTH_WEST(7, "south_west"),
          NORTH_WEST(8, "north_west"),
          NORTH_EAST(9, "north_east");
  
          private static final BlockRailBase.EnumRailDirection[] META_LOOKUP = new BlockRailBase.EnumRailDirection[values().length];
          private final int meta;
          private final String name;
  
          private EnumRailDirection(int meta, String name)
          {
              this.meta = meta;
              this.name = name;
          }
  
          public int getMetadata()
          {
              return this.meta;
          }
  
          public String toString()
          {
              return this.name;
          }
  
          public boolean isAscending()
          {
              return this == ASCENDING_NORTH || this == ASCENDING_EAST || this == ASCENDING_SOUTH || this == ASCENDING_WEST;
          }
  
          public static BlockRailBase.EnumRailDirection byMetadata(int meta)
          {
              if (meta < 0 || meta >= META_LOOKUP.length)
              {
                  meta = 0;
              }
  
              return META_LOOKUP[meta];
          }
  
          public String getName()
          {
              return this.name;
          }
  
          static
          {
              for (BlockRailBase.EnumRailDirection blockrailbase$enumraildirection : values())
              {
                  META_LOOKUP[blockrailbase$enumraildirection.getMetadata()] = blockrailbase$enumraildirection;
              }
          }
      }
  
      public class Rail
      {
          private final World world;
          private final BlockPos pos;
          private final BlockRailBase block;
          private IBlockState state;
          private final boolean isPowered;
          private final List<BlockPos> connectedRails = Lists.<BlockPos>newArrayList();
          private final boolean canMakeSlopes;
  
          public Rail(World worldIn, BlockPos pos, IBlockState state)
          {
              this.world = worldIn;
              this.pos = pos;
              this.state = state;
              this.block = (BlockRailBase)state.getBlock();
              BlockRailBase.EnumRailDirection blockrailbase$enumraildirection = block.getRailDirection(worldIn, pos, state, null);
              this.isPowered = !this.block.isFlexibleRail(worldIn, pos);
              this.canMakeSlopes = this.block.canMakeSlopes(worldIn, pos);
              this.updateConnectedRails(blockrailbase$enumraildirection);
          }
  
          public List<BlockPos> getConnectedRails()
          {
              return this.connectedRails;
          }
  
          private void updateConnectedRails(BlockRailBase.EnumRailDirection railDirection)
          {
              this.connectedRails.clear();
  
              switch (railDirection)
              {
                  case NORTH_SOUTH:
                      this.connectedRails.add(this.pos.north());
                      this.connectedRails.add(this.pos.south());
                      break;
                  case EAST_WEST:
                      this.connectedRails.add(this.pos.west());
                      this.connectedRails.add(this.pos.east());
                      break;
                  case ASCENDING_EAST:
                      this.connectedRails.add(this.pos.west());
                      this.connectedRails.add(this.pos.east().up());
                      break;
                  case ASCENDING_WEST:
                      this.connectedRails.add(this.pos.west().up());
                      this.connectedRails.add(this.pos.east());
                      break;
                  case ASCENDING_NORTH:
                      this.connectedRails.add(this.pos.north().up());
                      this.connectedRails.add(this.pos.south());
                      break;
                  case ASCENDING_SOUTH:
                      this.connectedRails.add(this.pos.north());
                      this.connectedRails.add(this.pos.south().up());
                      break;
                  case SOUTH_EAST:
                      this.connectedRails.add(this.pos.east());
                      this.connectedRails.add(this.pos.south());
                      break;
                  case SOUTH_WEST:
                      this.connectedRails.add(this.pos.west());
                      this.connectedRails.add(this.pos.south());
                      break;
                  case NORTH_WEST:
                      this.connectedRails.add(this.pos.west());
                      this.connectedRails.add(this.pos.north());
                      break;
                  case NORTH_EAST:
                      this.connectedRails.add(this.pos.east());
                      this.connectedRails.add(this.pos.north());
              }
          }
  
          private void removeSoftConnections()
          {
              for (int i = 0; i < this.connectedRails.size(); ++i)
              {
                  BlockRailBase.Rail blockrailbase$rail = this.findRailAt((BlockPos)this.connectedRails.get(i));
  
                  if (blockrailbase$rail != null && blockrailbase$rail.isConnectedToRail(this))
                  {
                      this.connectedRails.set(i, blockrailbase$rail.pos);
                  }
                  else
                  {
                      this.connectedRails.remove(i--);
                  }
              }
          }
  
          private boolean hasRailAt(BlockPos pos)
          {
              return BlockRailBase.isRailBlock(this.world, pos) || BlockRailBase.isRailBlock(this.world, pos.up()) || BlockRailBase.isRailBlock(this.world, pos.down());
          }
  
          @Nullable
          private BlockRailBase.Rail findRailAt(BlockPos pos)
          {
              IBlockState iblockstate = this.world.getBlockState(pos);
  
              if (BlockRailBase.isRailBlock(iblockstate))
              {
                  return BlockRailBase.this.new Rail(this.world, pos, iblockstate);
              }
              else
              {
                  BlockPos lvt_2_1_ = pos.up();
                  iblockstate = this.world.getBlockState(lvt_2_1_);
  
                  if (BlockRailBase.isRailBlock(iblockstate))
                  {
                      return BlockRailBase.this.new Rail(this.world, lvt_2_1_, iblockstate);
                  }
                  else
                  {
                      lvt_2_1_ = pos.down();
                      iblockstate = this.world.getBlockState(lvt_2_1_);
                      return BlockRailBase.isRailBlock(iblockstate) ? BlockRailBase.this.new Rail(this.world, lvt_2_1_, iblockstate) : null;
                  }
              }
          }
  
          private boolean isConnectedToRail(BlockRailBase.Rail rail)
          {
              return this.isConnectedTo(rail.pos);
          }
  
          private boolean isConnectedTo(BlockPos posIn)
          {
              for (int i = 0; i < this.connectedRails.size(); ++i)
              {
                  BlockPos blockpos = (BlockPos)this.connectedRails.get(i);
  
                  if (blockpos.getX() == posIn.getX() && blockpos.getZ() == posIn.getZ())
                  {
                      return true;
                  }
              }
  
              return false;
          }
  
          /**
           * Counts the number of rails adjacent to this rail.
           */
          protected int countAdjacentRails()
          {
              int i = 0;
  
              for (EnumFacing enumfacing : EnumFacing.Plane.HORIZONTAL)
              {
                  if (this.hasRailAt(this.pos.offset(enumfacing)))
                  {
                      ++i;
                  }
              }
  
              return i;
          }
  
          private boolean canConnectTo(BlockRailBase.Rail rail)
          {
              return this.isConnectedToRail(rail) || this.connectedRails.size() != 2;
          }
  
          private void connectTo(BlockRailBase.Rail p_150645_1_)
          {
              this.connectedRails.add(p_150645_1_.pos);
              BlockPos blockpos = this.pos.north();
              BlockPos blockpos1 = this.pos.south();
              BlockPos blockpos2 = this.pos.west();
              BlockPos blockpos3 = this.pos.east();
              boolean flag = this.isConnectedTo(blockpos);
              boolean flag1 = this.isConnectedTo(blockpos1);
              boolean flag2 = this.isConnectedTo(blockpos2);
              boolean flag3 = this.isConnectedTo(blockpos3);
              BlockRailBase.EnumRailDirection blockrailbase$enumraildirection = null;
  
              if (flag || flag1)
              {
                  blockrailbase$enumraildirection = BlockRailBase.EnumRailDirection.NORTH_SOUTH;
              }
  
              if (flag2 || flag3)
              {
                  blockrailbase$enumraildirection = BlockRailBase.EnumRailDirection.EAST_WEST;
              }
  
              if (!this.isPowered)
              {
  