text:
#include "tensorflow/core/grappler/optimizers/constant_folding.h"
#include "tensorflow/cc/ops/array_ops_internal.h"
#include "tensorflow/cc/ops/standard_ops.h"
#include "tensorflow/core/framework/node_def.pb.h"
#include "tensorflow/core/framework/tensor_testutil.h"
#include "tensorflow/core/grappler/grappler_item.h"
#include "tensorflow/core/grappler/utils.h"
#include "tensorflow/core/grappler/utils/grappler_test.h"
#include "tensorflow/core/lib/core/status_test_util.h"
#include "tensorflow/core/lib/strings/strcat.h"

namespace tensorflow {
namespace grappler {
namespace {

class ConstantFoldingTest : public GrapplerTest {};

TEST_F(ConstantFoldingTest, SimpleFolding) {
  // Build a simple graph with a few trivially prunable ops.
  tensorflow::Scope s = tensorflow::Scope::NewRootScope();

  Output a = ops::Const(s.WithOpName("a"), 1.0f, {1});
  Output b = ops::Const(s.WithOpName("b"), 2.0f, {1});
  Output c = ops::AddN(s.WithOpName("c").WithDevice("/CPU:0"), {a, b});
  Output d = ops::AddN(s.WithOpName("d"), {b, c});

  GrapplerItem item;
  item.fetch.push_back("d");
  TF_CHECK_OK(s.ToGraphDef(&item.graph));

  ConstantFolding fold(nullptr /* cpu_device */);
  GraphDef output;
  Status status = fold.Optimize(nullptr, item, &output);
  TF_EXPECT_OK(status);

  EXPECT_EQ(1, output.node_size());

  const NodeDef& node_d = output.node(0);
  EXPECT_EQ("d", node_d.name());
  EXPECT_EQ("Const", node_d.op());

  std::vector<string> fetch = {"d"};
  auto tensors_expected = EvaluateNodes(item.graph, fetch);
  auto tensors = EvaluateNodes(output, fetch);
  EXPECT_EQ(1, tensors_expected.size());
  EXPECT_EQ(1, tensors.size());
  test::ExpectTensorEqual<float>(tensors_expected[0], tensors[0]);
}

TEST_F(ConstantFoldingTest, AddTree) {
  tensorflow::Scope s = tensorflow::Scope::NewRootScope();

  Output c2 = ops::Const(s.WithOpName("c2"), 2.0f, {2});
  Output c3 = ops::Const(s.WithOpName("c3"), 3.0f, {2});
  Output x = ops::Placeholder(s.WithOpName("x"), DT_FLOAT,
                              ops::Placeholder::Shape(TensorShape({2, 2})));
  Output add_child = ops::Add(s.WithOpName("add_child"), c2, x);
  Output c1 = ops::Const(s.WithOpName("c1").WithControlDependencies(add_child),
                         1.0f, {1});
  Output add_parent = ops::Add(s.WithOpName("add_parent"), c1, add_child);

  Output y = ops::Placeholder(s.WithOpName("y"), DT_FLOAT,
                              ops::Placeholder::Shape(TensorShape({2, 2})));
  Output c4 = ops::Const(s.WithOpName("c4"), 4.0f, {2});
  Output c5 = ops::Const(s.WithOpName("c5"), 5.0f, {2});
  Output c20 = ops::Const(s.WithOpName("c20"), 20.0f, {2});
  Output mul_child = ops::Mul(s.WithOpName("mul_child"), c4, y);
  Output mul_parent = ops::Mul(s.WithOpName("mul_parent"), c5, mul_child);
  Output addmul_child = ops::Add(s.WithOpName("addmul_child"), c4, x);
  Output addmul_parent =
      ops::Mul(s.WithOpName("addmul_parent"), c5, addmul_child);

  GrapplerItem item;
  item.fetch = {"add_parent", "mul_parent", "addmul_parent"};
  TF_CHECK_OK(s.ToGraphDef(&item.graph));

  ConstantFolding fold(nullptr /* cpu_device */);
  GraphDef output;
  Status status = fold.Optimize(nullptr, item, &output);
  TF_EXPECT_OK(status);

  // We expect the following rewrite(s) to occur:
  //
  //    +                +             +
  //   / \              / \           / \
  // 1.0  +     -->    x   +    -->  x  3.0
  //     / \              / \
  //   2.0  x           1.0 2.0
  //
  //    *                *             *
  //   / \              / \           / \
  // 4.0  *     -->    y   *    -->  y  20.0
  //     / \              / \
  //   5.0  y           4.0 5.0

  EXPECT_EQ(11, output.node_size());
  for (const auto& node : output.node()) {
    if (node.name() == "add_child") {
      EXPECT_EQ("Const", node.op());
      TensorProto t = node.attr().at("value").tensor();
      EXPECT_EQ(1, t.tensor_shape().dim_size());
      EXPECT_EQ(2, t.tensor_shape().dim(0).size());
    } else if (node.name() == "add_parent") {
      EXPECT_EQ("Add", node.op());
      EXPECT_EQ(2, node.input_size());
      EXPECT_EQ("x", node.input(0));
      EXPECT_EQ("add_child", node.input(1));
    } else if (node.name() == "mul_child") {
      EXPECT_EQ("Const", node.op());
      TensorProto t = node.attr().at("value").tensor();
      EXPECT_EQ(1, t.tensor_shape().dim_size());
      EXPECT_EQ(2, t.tensor_shape().dim(0).size());
    } else if (node.name() == "mul_parent") {
      EXPECT_EQ("Mul", node.op());
      EXPECT_EQ(2, node.input_size());
      EXPECT_EQ("y", node.input(0));
      EXPECT_EQ("mul_child", node.input(1));
    } else if (node.name() == "addmul_child") {
      // Unchanged.
      EXPECT_EQ("Add", node.op());
      EXPECT_EQ(2, node.input_size());
      EXPECT_EQ("c4", node.input(0));
      EXPECT_EQ("x", node.input(1));
    }
  }

  // Check that the result nodes have the expected value.
  std::vector<string> fetch = {"c3", "c20"};
  auto tensor_expected = EvaluateNodes(item.graph, fetch);
  EXPECT_EQ(fetch.size(), tensor_expected.size());
  fetch = {"add_child", "mul_child"};
  auto tensors = EvaluateNodes(output, fetch);
  EXPECT_EQ(fetch.size(), tensors.size());
  for (int i = 0; i < fetch.size(); i++) {
    test::ExpectTensorEqual<float>(tensor_expected[i], tensors[i]);
  }
}

TEST_F(ConstantFoldingTest, NeutralElement) {
  for (bool use_const : {true, false}) {
    tensorflow::Scope s = tensorflow::Scope::NewRootScope();
    Output x = ops::Placeholder(s.WithOpName("x"), DT_FLOAT,
                                ops::Placeholder::Shape(TensorShape({2, 2})));
    Output y = ops::Placeholder(s.WithOpName("y"), DT_FLOAT,
                                ops::Placeholder::Shape(TensorShape({2, 2})));
    Output a = ops::Placeholder(s.WithOpName("a"), DT_FLOAT,
                                ops::Placeholder::Shape(TensorShape({3, 2})));
    Output b = ops::Placeholder(s.WithOpName("b"), DT_FLOAT,
                                ops::Placeholder::Shape(TensorShape({2, 3})));
    Output bias = ops::Placeholder(s.WithOpName("bias"), DT_FLOAT,
                                   ops::Placeholder::Shape(TensorShape({2})));
    Output zeros = !use_const ? ops::ZerosLike(s.WithOpName("zeros"), x)
                              : ops::Const(s.WithOpName("zeros"), 0.0f, {2, 2});
    Output zeros_1d = ops::Const(s.WithOpName("zeros_1d"), 0.0f, {2});
    Output ones = !use_const ? ops::OnesLike(s.WithOpName("ones"), x)
                             : ops::Const(s.WithOpName("ones"), 1.0f, {2, 2});
    Output mul1 = ops::Mul(s.WithOpName("mul1"), x, zeros);
    Output mul2 = ops::Mul(s.WithOpName("mul2"), zeros, y);
    Output mul3 = ops::Mul(s.WithOpName("mul3"), x, ones);
    Output mul4 = ops::Mul(s.WithOpName("mul4"), ones, y);
    Output mul5 = ops::Mul(s.WithOpName("mul5"), x, zeros_1d);
    Output mul6 = ops::Mul(s.WithOpName("mul6"), zeros_1d, y);
    Output div1 = ops::Div(s.WithOpName("div1"), x, ones);
    Output div2 = ops::Div(s.WithOpName("div2"), ones, y);
    Output matmul1 = ops::MatMul(s.WithOpName("matmul1"), x, zeros);
    Output matmul2 = ops::MatMul(s.WithOpName("matmul2"), zeros, y);
    Output matmul3 = ops::MatMul(s.WithOpName("matmul3"), a, zeros);
    Output matmul4 = ops::MatMul(s.WithOpName("matmul4"), zeros, b);
    Output add1 = ops::Add(s.WithOpName("add1"), x, zeros);
    Output add2 = ops::Add(s.WithOpName("add2"), zeros, y);
    Output bias_add1 = ops::BiasAdd(s.WithOpName("bias_add1"), x, zeros_1d);
    Output bias_add2 = ops::BiasAdd(s.WithOpName("bias_add2"), zeros, bias);
    Output sub1 = ops::Sub(s.WithOpName("sub1"), x, zeros);
    Output sub2 = ops::Sub(s.WithOpName("sub2"), zeros, y);
    Output addn =
        ops::AddN(s.WithOpName("addn"),
                  {mul1, mul2, mul3, mul4, mul5, mul6, div1, div2, matmul1,
                   matmul2, add1, add2, bias_add1, bias_add2, sub1, sub2});
    GrapplerItem item;
    TF_CHECK_OK(s.ToGraphDef(&item.graph));
    item.fetch = {"addn", "matmul3", "matmul4"};

    ConstantFolding optimizer(RewriterConfig::AGGRESSIVE,
                              nullptr /* cpu_device */);
    GraphDef output;
    Status status = optimizer.Optimize(nullptr, item, &output);
    TF_EXPECT_OK(status);

    EXPECT_EQ(27, output.node_size());
    for (int i = 0; i < output.node_size(); ++i) {
      const NodeDef& node = output.node(i);
      const string& name = node.name();
      if (name == "mul1") {
        EXPECT_EQ("Const", node.op());
        EXPECT_EQ("^x", node.input(0));
        EXPECT_EQ("^zeros", node.input(1));
      } else if (name == "mul2") {
        EXPECT_EQ("Const", node.op());
        EXPECT_EQ("^zeros", node.input(0));
        EXPECT_EQ("^y", node.input(1));
      } else if (name == "mul3") {
        EXPECT_EQ("Identity", node.op());
        EXPECT_EQ("x", node.input(0));
        EXPECT_EQ("^ones", node.input(1));
      } else if (name == "mul4") {
        EXPECT_EQ("Identity", node.op());
        EXPECT_EQ("y", node.input(0));
        EXPECT_EQ("^ones", node.input(1));
      } else if (name == "mul5") {
        EXPECT_EQ("Const", node.op());
        EXPECT_EQ("^x", node.input(0));
        EXPECT_EQ("^zeros_1d", node.input(1));
      } else if (name == "mul6") {
        EXPECT_EQ("Const", node.op());
        EXPECT_EQ("^zeros_1d", node.input(0));
        EXPECT_EQ("^y", node.input(1));
      } else if (name == "div1") {
        EXPECT_EQ("Identity", node.op());
        EXPECT_EQ("x", node.input(0));
        EXPECT_EQ("^ones", node.input(1));
      } else if (name == "div2") {
        EXPECT_EQ("Reciprocal", node.op());
        EXPECT_EQ("y", node.input(0));
        EXPECT_EQ("^ones", node.input(1));
      } else if (name == "matmul1") {
        EXPECT_EQ("Const", node.op());
        EXPECT_EQ("^x", node.input(0));
        EXPECT_EQ("^zeros", node.input(1));
      } else if (name == "matmul2") {
        EXPECT_EQ("Const", node.op());
        EXPECT_EQ("^zeros", node.input(0));
        EXPECT_EQ("^y", node.input(1));
      } else if (name == "matmul3") {
        EXPECT_EQ("Const", node.op());
        EXPECT_EQ("^a", node.input(0));
        EXPECT_EQ("^zeros", node.input(1));
        TensorProto t = node.attr().at("value").tensor();
        EXPECT_EQ(1, t.float_val_size());
        EXPECT_EQ(0, t.float_val(0));
        EXPECT_EQ(2, t.tensor_shape().dim_size());
        EXPECT_EQ(3, t.tensor_shape().dim(0).size());
        EXPECT_EQ(2, t.tensor_shape().dim(1).size());
      } else if (name == "matmul4") {
        EXPECT_EQ("Const", node.op());
        EXPECT_EQ("^zeros", node.input(0));
        EXPECT_EQ("^b", node.input(1));
        TensorProto t = node.attr().at("value").tensor();
        EXPECT_EQ(1, t.float_val_size());
        EXPECT_EQ(0, t.float_val(0));
        EXPECT_EQ(2, t.tensor_shape().dim_size());
        EXPECT_EQ(2, t.tensor_shape().dim(0).size());
        EXPECT_EQ(3, t.tensor_shape().dim(1).size());
      } else if (name == "add1") {
        EXPECT_EQ("Identity", node.op());
        EXPECT_EQ("x", node.input(0));
        EXPECT_EQ("^zeros", node.input(1));
      } else if (name == "add2") {
        EXPECT_EQ("Identity", node.op());
        EXPECT_EQ("y", node.input(0));
        EXPECT_EQ("^zeros", node.input(1));
      } else if (name == "bias_add1") {
        EXPECT_EQ("Identity", node.op());
        EXPECT_EQ("x", node.input(0));
        EXPECT_EQ("^zeros_1d", node.input(1));
      } else if (name == "bias_add2") {
        // We don't eliminate this one, because it requires broadcasting.
        EXPECT_EQ("BiasAdd", node.op());
        EXPECT_EQ("zeros", node.input(0));
        EXPECT_EQ("bias", node.input(1));
      } else if (name == "sub1") {
        EXPECT_EQ("Identity", node.op());
        EXPECT_EQ("x", node.input(0));
        EXPECT_EQ("^zeros", node.input(1));
      } else if (name == "sub2") {
        // We don't handle this case yet.
        EXPECT_EQ("Sub", node.op());
        EXPECT_EQ("zeros", node.input(0));
        EXPECT_EQ("y", node.input(1));
      }
      const std::set<string> square_zero_const{"mul1", "mul2",    "mul5",
                                               "mul6", "matmul1", "matmul2"};
      if (square_zero_const.count(name) > 0) {
        TensorProto t = node.attr().at("value").tensor();
        EXPECT_EQ(1, t.float_val_size());
        EXPECT_EQ(0, t.float_val(0));
        EXPECT_EQ(2, t.tensor_shape().dim_size());
        EXPECT_EQ(2, t.tensor_shape().dim(0).size());
        EXPECT_EQ(2, t.tensor_shape().dim(1).size());
      }
    }
  }
}

TEST_F(ConstantFoldingTest, StrengthReduce_Reciprocal) {
  tensorflow::Scope s = tensorflow::Scope::NewRootScope();
  Output cf_half = ops::Const(s.WithOpName("cf_half"), 0.5f, {1});
  Output xf = ops::Placeholder(s.WithOpName("xf"), DT_FLOAT,
                               ops::Placeholder::Shape(TensorShape({2, 2})));
  Output xi = ops::Placeholder(s.WithOpName("xi"), DT_INT32,
                               ops::Placeholder::Shape(TensorShape({2, 2})));
  Output ci = ops::Const(s.WithOpName("ci"), 2, {1});
  Output cf = ops::Const(s.WithOpName("cf"), 2.0f, {1});
  Output div_i = ops::Div(s.WithOpName("div_i"), xi, ci);
  Output div_f = ops::Div(s.WithOpName("div_f"), xf, cf);
  Output realdiv = ops::RealDiv(s.WithOpName("realdiv"), xf, cf);

  GrapplerItem item;
  TF_CHECK_OK(s.ToGraphDef(&item.graph));
  item.fetch = {"div_f", "div_i", "realdiv"};
  ConstantFolding optimizer(RewriterConfig::AGGRESSIVE,
                            nullptr /* cpu_device */);
  GraphDef output;
  Status status = optimizer.Optimize(nullptr, item, &output);
  TF_EXPECT_OK(status);

  EXPECT_EQ(8, output.node_size());
  for (int i = 0; i < output.node_size(); ++i) {
    const NodeDef& node = output.node(i);
    const string& name = node.name();
    if (name == "div_i") {
      // Integer division is unchanged.
      EXPECT_EQ("Div", node.op());
      EXPECT_EQ("xi", node.input(0));
      EXPECT_EQ("ci", node.input(1));
    } else if (name == "div_f") {
      EXPECT_EQ("Mul", node.op());
      EXPECT_EQ("xf", node.input(0));
      EXPECT_EQ("ConstantFolding/div_f_recip", node.input(1));
    } else if (name == "realdiv") {
      EXPECT_EQ("Mul", node.op());
      EXPECT_EQ("xf", node.input(0));
      EXPECT_EQ("ConstantFolding/realdiv_recip", node.input(1));
    } else if (name == "ConstantFolding/div_f_recip") {
      EXPECT_EQ("Const", node.op());
      EXPECT_EQ(DT_FLOAT, node.attr().at("dtype").type());
      TensorProto t = node.attr().at("value").tensor();
      EXPECT_EQ(DT_FLOAT, t.dtype());
      EXPECT_EQ(1, t.tensor_shape().dim_size());
      EXPECT_EQ(1, t.tensor_shape().dim(0).size());
    } else if (name == "ConstantFolding/realdiv_recip") {
      EXPECT_EQ("Const", node.op());
      EXPECT_EQ(DT_FLOAT, node.attr().at("dtype").type());
      TensorProto t = node.attr().at("value").tensor();
      EXPECT_EQ(DT_FLOAT, t.dtype());
      EXPECT_EQ(1, t.tensor_shape().dim_size());
      EXPECT_EQ(1, t.tensor_shape().dim(0).size());
    }
  }

  // Check that the reciprocals have the expected value.
  std::vector<string> fetch = {"cf_half"};
  auto tensor_expected = EvaluateNodes(item.graph, fetch);
  EXPECT_EQ(fetch.size(), tensor_expected.size());
  fetch = {"ConstantFolding/div_f_recip", "ConstantFolding/realdiv_recip"};
  auto tensors = EvaluateNodes(output, fetch);
  EXPECT_EQ(fetch.size(), tensors.size());
  for (int i = 0; i < fetch.size(); i++) {
    test::ExpectTensorEqual<float>(tensor_expected[0], tensors[i]);
  }
}

TEST_F(ConstantFoldingTest, NeutralElement_PartialShape_UnknownOutputShape) {
  tensorflow::Scope s = tensorflow::Scope::NewRootScope();
  Output x_known =
      ops::Placeholder(s.WithOpName("x_known"), DT_FLOAT,
                       ops::Placeholder::Shape(TensorShape({2, 2})));
  Output x_partially_known =
      ops::Placeholder(s.WithOpName("x_partially_unknown"), DT_FLOAT,
                       ops::Placeholder::Shape(PartialTensorShape({-1, -1})));
  Output x_unknown = ops::Placeholder(s.WithOpName("x_unknown"), DT_FLOAT);
  Output zeros_known = ops::ZerosLike(s.WithOpName("zeros_known"), x_known);
  Output zeros_partially_known =
      ops::ZerosLike(s.WithOpName("zeros_partially_known"), x_partially_known);
  Output zeros_unknown =
      ops::ZerosLike(s.WithOpName("zeros_unknown"), x_unknown);

  // Multiplies without any additional ops to supply the output shape.
  int count = 0;
  std::vector<Output> muls;
  std::unordered_set<string> not_converted;
  std::unordered_set<string> to_const;
  std::unordered_set<string> to_identity;
  for (const auto* x : {&x_known, &x_partially_known, &x_unknown}) {
    for (const auto* zeros :
         {&zeros_known, &zeros_partially_known, &zeros_unknown}) {
      const string name = strings::StrCat("mul_", count++);
      muls.push_back(ops::Mul(s.WithOpName(name), *x, *zeros));
      if (x == &x_partially_known && zeros == &zeros_partially_known) {
        to_identity.insert(name);
      } else if (x == &x_unknown || zeros == &zeros_unknown) {
        not_converted.insert(name);
      } else {
        to_const.insert(name);
      }
    }
  }

  GrapplerItem item;
  TF_CHECK_OK(s.ToGraphDef(&item.graph));

  ConstantFolding optimizer(RewriterConfig::AGGRESSIVE,
                            nullptr /* cpu_device */);
  GraphDef output;
  Status status = optimizer.Optimize(nullptr, item, &output);
  TF_EXPECT_OK(status);
  LOG(INFO) << output.DebugString();

  EXPECT_EQ(15, output.node_size());
  for (int i = 0; i < output.node_size(); ++i) {
    const NodeDef& node = output.node(i);
    const string& name = node.name();
    if (to_const.count(name) > 0) {
      EXPECT_EQ("Const", node.op()) << node.name();
    } else if (to_identity.count(name) > 0) {
      EXPECT_EQ("Identity", node.op()) << node.name();
    } else if (not_converted.count(name) > 0) {
      EXPECT_EQ("Mul", node.op()) << node.name();
    }
  }
}

TEST_F(ConstantFoldingTest, NeutralElement_PartialShape_KnownOutputShape) {
  tensorflow::Scope s = tensorflow::Scope::NewRootScope();
  Output known_shape = ops::Const(s.WithOpName("known_shape"), 0.0f, {2, 2});
  Output x_partially_known =
      ops::Placeholder(s.WithOpName("x_partially_unknown"), DT_FLOAT,
                       ops::Placeholder::Shape(PartialTensorShape({-1, -1})));
  Output x_unknown = ops::Placeholder(s.WithOpName("x_unknown"), DT_FLOAT);
  Output zeros_partially_known =
      ops::ZerosLike(s.WithOpName("zeros_partially_known"), x_partially_known);
  Output zeros_unknown =
      ops::ZerosLike(s.WithOpName("zeros_unknown"), x_unknown);

  // If at least one of the inputs to AddN has a known shape, shape inference
  // will propagate the shape back to the inputs of AddN, making the
  // output shapes of all its inputs known
  std::vector<Output> muls_deduced_output_shape;
  std::unordered_set<string> to_const;
  int count = 0;
  for (const auto& x : {x_partially_known, x_unknown}) {
    for (const auto& zeros : {zeros_partially_known, zeros_unknown}) {
      const string name = strings::StrCat("mul_", count++);
      muls_deduced_output_shape.push_back(
          ops::Mul(s.WithOpName(name), x, zeros));
      to_const.insert(name);
    }
  }
  // We add a known shape as input to AddN to propagate it back to the
  // multiplies above, which means they can all be turned into Const nodes.
  muls_deduced_output_shape.push_back(known_shape);
  Output addn1 = ops::AddN(s.WithOpName("addn1"), muls_deduced_output_shape);

  GrapplerItem item;
  TF_CHECK_OK(s.ToGraphDef(&item.graph));

  ConstantFolding optimizer(RewriterConfig::AGGRESSIVE,
                            nullptr /* cpu_device */);
  GraphDef output;
  Status status = optimizer.Optimize(nullptr, item, &output);
  TF_EXPECT_OK(status);
  LOG(INFO) << output.DebugString();

  EXPECT_EQ(10, output.node_size());
  for (int i = 0; i < output.node_size(); ++i) {
    const NodeDef& node = output.node(i);
    const string& name = node.name();
    if (to_const.count(name) > 0) {
      EXPECT_EQ("Const", node.op()) << node.name();
      EXPECT_EQ(2, node.input_size());
      EXPECT_TRUE(IsControlInput(node.input(0)));
      EXPECT_TRUE(IsControlInput(node.input(1)));
    }
  }
}

TEST_F(ConstantFoldingTest, CreateConstNodes) {
  tensorflow::Scope s = tensorflow::Scope::NewRootScope();

#define MAKE_TEST_GRAPH(TYPE)                                               \
  Output TYPE##_const =                                                     \
      ops::Const(s.WithOpName(#TYPE "_const"), static_cast<TYPE>(10), {5}); \
  Output TYPE##_mul =                                                       \
      ops::Mul(s.WithOpName(#TYPE "_mul"), TYPE##_const, TYPE##_const);     \
  Output TYPE##_id = ops::Identity(s.WithOpName(#TYPE "_id"), TYPE##_mul)

  MAKE_TEST_GRAPH(float);
  MAKE_TEST_GRAPH(double);
  MAKE_TEST_GRAPH(int64);
  MAKE_TEST_GRAPH(int32);
  MAKE_TEST_GRAPH(int16);
  MAKE_TEST_GRAPH(int8);
  MAKE_TEST_GRAPH(uint8);
#undef MAKE_TEST_GRAPH

  Output bool_const = ops::Const(s.WithOpName("bool_const"), true, {5});
  Output bool_and =
      ops::LogicalAnd(s.WithOpName("bool_and"), bool_const, bool_const);
  Output bool_id = ops::Identity(s.WithOpName("bool_id"), bool_and);

  GrapplerItem item;
  TF_CHECK_OK(s.ToGraphDef(&item.graph));
  ConstantFolding fold(nullptr /* cpu_device */);
  GraphDef output;
  Status status = fold.Optimize(nullptr, item, &output);
  TF_EXPECT_OK(status);

  EXPECT_EQ(24, output.node_size());
  for (const NodeDef& node : output.node()) {
#define CHECK_RESULT(TYPE, FIELD)                                             \
  if (node.name() == #TYPE "_mul") {                                          \
    EXPECT_EQ(5,                                                              \
              node.attr().at("value").tensor().tensor_shape().dim(0).size()); \
    EXPECT_EQ(1, node.attr().at("value").tensor().FIELD##_val_size());        \
    EXPECT_EQ(10 * 10, node.attr().at("value").tensor().FIELD##_val(0));      \
  }

    CHECK_RESULT(float, float);
    CHECK_RESULT(double, double);
    CHECK_RESULT(int64, int64);
    CHECK_RESULT(int32, int);
    CHECK_RESULT(int16, int);
    CHECK_RESULT(int8, int);
    CHECK_RESULT(uint8, int);
#undef CHECK_RESULT

    if (node.name() == "bool_and") {
      EXPECT_EQ(5,
                node.attr().at("value").tensor().tensor_shape().dim(0).size());
      EXPECT_EQ(1, node.attr().at("value").tensor().bool_val_size());
      EXPECT_EQ(true && true, node.attr().at("value").tensor().bool_val(0));
    }
  }
}

TEST_F(ConstantFoldingTest, FoldingNodeWithTwoOutputs) {
  // Build a simple graph with a few trivially prunable ops.
  tensorflow::Scope s = tensorflow::Scope::NewRootScope();

  Output a = ops::Const(s.WithOpName("a"), 10, {5});
  auto b = ops::Unique(s.WithOpName("b"), {a});
  Output c = ops::Identity(s.WithOpName("c"), {b.y});
  Output d = ops::Identity(s.WithOpName("d"), {b.idx});
  Output e = ops::Identity(s.WithOpName("e"), {c});
  Output f = ops::Identity(s.WithOpName("f"), {d});

  GrapplerItem item;
  item.fetch.push_back("e");
  item.fetch.push_back("f");
  TF_CHECK_OK(s.ToGraphDef(&item.graph));

  ConstantFolding fold(nullptr /* cpu_device */);
  GraphDef output;
  Status status = fold.Optimize(nullptr, item, &output);
  TF_EXPECT_OK(status);

  EXPECT_EQ(2, output.node_size());

  const NodeDef& new_c = output.node(0);
  EXPECT_EQ("e", new_c.name());
  EXPECT_EQ("Const", new_c.op());

  const NodeDef& new_d = output.node(1);
  EXPECT_EQ("f", new_d.name());
  EXPECT_EQ("Const", new_d.op());

  std::vector<string> fetch = {"e", "f"};
  auto tensors_expected = EvaluateNodes(item.graph, fetch);
  auto tensors = EvaluateNodes(output, fetch);
  EXPECT_EQ(fetch.size(), tensors_expected.size());
  EXPECT_EQ(fetch.size(), tensors.size());
  for (int i = 0; i < fetch.size(); i++) {
    test::ExpectTensorEqual<int>(tensors_expected[i], tensors[i]);
  }
}

TEST_F(ConstantFoldingTest, ControlDependencies) {
  tensorflow::Scope scope = tensorflow::Scope::NewRootScope();
  Output dflt = ops::Const(scope.WithOpName("dflt"), 3.14f, {1});
  Output p1 = ops::PlaceholderWithDefault(scope.WithOpName("p1"), dflt, {1});
  Output p2 = ops::PlaceholderWithDefault(scope.WithOpName("p2"), dflt, {1});
  Output c =
      ops::Const(scope.WithOpName("c").WithControlDependencies(p1), 10, {3});
  Output i1 = ops::Identity(scope.WithOpName("i1"), {c});
  Output i2 =
      ops::Identity(scope.WithOpName("i2").WithControlDependencies(p2), {i1});
  Output i3 = ops::Identity(scope.WithOpName("e"), {i2});

  GrapplerItem item;
  item.fetch.push_back("e");
  TF_CHECK_OK(scope.ToGraphDef(&item.graph));

  ConstantFolding fold(nullptr /* cpu_device */);
  GraphDef output;
  Status status = fold.Optimize(nullptr, item, &output);
  TF_EXPECT_OK(status);

  std::vector<string> expected_nodes = {"dflt", "p1", "p2", "e"};
  EXPECT_EQ(output.node_size(), expected_nodes.size());
  int i = 0;
  int found = 0;
  for (const auto& node : output.node()) {
    EXPECT_EQ(expected_nodes[i], output.node(i).name());
    i++;
    if (node.name() == "e") {
      EXPECT_EQ("Const", node.op());
      ++found;
      auto folded = EvaluateNodes(output, {"e"});
      auto expected = EvaluateNodes(item.graph, {"e"});
      EXPECT_EQ(1, expected.size());
      EXPECT_EQ(1, folded.size());
      test::ExpectTensorEqual<int>(folded[0], expected[0]);
      EXPECT_EQ(2, node.input_size());
      EXPECT_EQ("^p1", node.input(0));
      EXPECT_EQ("^p2", node.input(1));
    }
  }
  EXPECT_EQ(1, found);
}

TEST_F(ConstantFoldingTest, ControlDependenciesEmptyFetch) {
  tensorflow::Scope scope = tensorflow::Scope::NewRootScope();
  Output dflt = ops::Const(scope.WithOpName("dflt"), 3.14f, {1});
  Output p1 = ops::PlaceholderWithDefault(scope.WithOpName("p1"), dflt, {1});
  Output p2 = ops::PlaceholderWithDefault(scope.WithOpName("p2"), dflt, {1});
  Output c =
      ops::Const(scope.WithOpName("c").WithControlDependencies(p1), 10, {3});
  Output i1 = ops::Identity(scope.WithOpName("i1"), {c});
  Output i2 =
      ops::Identity(scope.WithOpName("i2").WithControlDependencies(p2), {i1});
  Output i3 = ops::Identity(scope.WithOpName("e"), {i2});

  GrapplerItem item;
  TF_CHECK_OK(scope.ToGraphDef(&item.graph));

  ConstantFolding fold(nullptr /* cpu_device */);
  GraphDef output;
  Status status = fold.Optimize(nullptr, item, &output);
  TF_EXPECT_OK(status);

  std::vector<string> expected_nodes = {"dflt", "p1", "p2", "c",
                                        "i1",   "i2", "e"};
  EXPECT_EQ(output.node_size(), expected_nodes.size());
  int i = 0;
  int found = 0;
  for (const auto& node : output.node()) {
    EXPECT_EQ(expected_nodes[i], output.node(i).name());
    i++;
    if (node.name() == "i1") {
      EXPECT_EQ("Const", node.op());
      ++found;
      auto folded = EvaluateNodes(output, {"i1"});
      auto expected = EvaluateNodes(item.graph, {"i1"});
      EXPECT_EQ(1, expected.size());
      EXPECT_EQ(1, folded.size());
      test::ExpectTensorEqual<int>(folded[0], expected[0]);
      EXPECT_EQ(1, node.input_size());
      EXPECT_EQ("^p1", node.input(0));
    }
    if (node.name() == "i2") {
      EXPECT_EQ("Const", node.op());
      ++found;
      auto folded = EvaluateNodes(output, {"i2"});
      auto expected = EvaluateNodes(item.graph, {"i2"});
      EXPECT_EQ(1, expected.size());
      EXPECT_EQ(1, folded.size());
      test::ExpectTensorEqual<int>(folded[0], expected[0]);
      EXPECT_EQ(2, node.input_size());
      EXPECT_EQ("^p1", node.input(0));
      EXPECT_EQ("^p2", node.input(1));
    }
  }
  EXPECT_EQ(2, found);
}

TEST_F(ConstantFoldingTest, ControlDependenciesDeduplicate) {
  tensorflow::Scope scope = tensorflow::Scope::NewRootScope();
  Output dflt = ops::Const(scope.WithOpName("dflt"), 3.14f, {1});
  Output p1 = ops::PlaceholderWithDefault(scope.WithOpName("p1"), dflt, {1});
  Output p2 = ops::PlaceholderWithDefault(scope.WithOpName("p2"), dflt, {1});
  Output c =
      ops::Const(scope.WithOpName("c").WithControlDependencies(p1), 10, {3});
  Output i1 = ops::Identity(scope.WithOpName("i1")
                                .WithControlDependencies(p2)
                                .WithControlDependencies(p1),
                            {c});
  Output i2 = ops::Identity(scope.WithOpName("i2"), {i1});

  GrapplerItem item;
  item.fetch.push_back("i2");
  TF_CHECK_OK(scope.ToGraphDef(&item.graph));

  ConstantFolding fold(nullptr /* cpu_device */);
  GraphDef output;
  Status status = fold.Optimize(nullptr, item, &output);
  TF_EXPECT_OK(status);

  std::vector<string> expected_nodes = {"dflt", "p1", "p2", "i2"};
  EXPECT_EQ(output.node_size(), expected_nodes.size());
  int i = 0;
  for (const auto& node : output.node()) {
    EXPECT_EQ(expected_nodes[i], output.node(i).name());
    i++;
    if (node.name() == "i2") {
      EXPECT_EQ("Const", node.op());
      EXPECT_EQ(2, node.input_size());
      EXPECT_EQ("^p1", node.input(0));
      EXPECT_EQ("^p2", node.input(1));
    }
  }
}

TEST_F(ConstantFoldingTest, VariableNumberOfOutputs) {
  tensorflow::Scope scope = tensorflow::Scope::NewRootScope();
  // Add a DynamicPartition node to the graph
  Output input = ops::Const(scope.WithOpName("in0"), 314, {3, 4, 5});
  Output indices = ops::Const(scope.WithOpName("indices"), 1, {3, 4});
  int num_partitions = 4;
  ops::DynamicPartition part(scope.WithOpName("partition"), input, indices,
                             num_partitions);

  std::vector<string> outputs;
  for (int i = 0; i < num_partitions; ++i) {
    string part_out_name = strings::StrCat("part_out", i);
    ops::Identity partition_out(scope.WithOpName(part_out_name),
                                {part.outputs[i]});
    outputs.push_back(part_out_name);
  }

  GrapplerItem item;
  TF_CHECK_OK(scope.ToGraphDef(&item.graph));

  // Add a ConcatOffset node to the graph
  Tensor initial_val(DT_INT32, TensorShape({3}));
  test::FillIota<int>(&initial_val, 7);
  for (int i = 1; i < 5; ++i) {
    TF_CHECK_OK(NodeDefBuilder(strings::StrCat("in", i), "Const")
                    .Attr("dtype", DT_INT32)
                    .Attr("value", initial_val)
                    .Finalize(item.graph.add_node()));
  }
  Tensor concat_dim(DT_INT32, TensorShape({}));
  test::FillIota<int>(&concat_dim, 0);
  TF_CHECK_OK(NodeDefBuilder("concat_dim", "Const")
                  .Attr("dtype", DT_INT32)
                  .Attr("value", concat_dim)
                  .Finalize(item.graph.add_node()));

  TF_CHECK_OK(NodeDefBuilder("concat_offsets", "ConcatOffset")
                  .Input("concat_dim", 0, DT_INT32)
                  .Input({NodeDefBuilder::NodeOut("in1", 0, DT_INT32),
                          NodeDefBuilder::NodeOut("in2", 0, DT_INT32),
                          NodeDefBuilder::NodeOut("in3", 0, DT_INT32),
                          NodeDefBuilder::NodeOut("in4", 0, DT_INT32)})
                  .Finalize(item.graph.add_node()));

  for (int i = 0; i < 4; ++i) {
    string concat_offset_out_name = strings::StrCat("concat_offset_out", i);
    TF_CHECK_OK(NodeDefBuilder(concat_offset_out_name, "Identity")
                    .Attr("T", DT_INT32)
                    .Input("concat_offsets", i, DT_INT32)
                    .Finalize(item.graph.add_node()));
    outputs.push_back(concat_offset_out_name);
  }

  item.fetch = outputs;
  ConstantFolding fold(nullptr /* cpu_device */);
  GraphDef output;
  Status status = fold.Optimize(nullptr, item, &output);
  TF_EXPECT_OK(status);

  int constant_folded = 0;
  for (const auto& node : output.node()) {
    if (node.name().find("part_out") != string::npos ||
        node.name().find("concat_offset_out") != string::npos) {
      ++constant_folded;
      EXPECT_EQ("Const", node.op());
    }
  }
  EXPECT_EQ(8, constant_folded);

  auto expected = EvaluateNodes(item.graph, outputs);
  auto optimized = EvaluateNodes(output, outputs);
  ASSERT_EQ(expected.size(), optimized.size());
  for (int i = 0; i < expected.size(); ++i) {
    test::ExpectTensorEqual<int>(expected[i], optimized[i]);
  }
}

TEST_F(ConstantFoldingTest, ShapeMaterialization) {
  tensorflow::Scope scope = tensorflow::Scope::NewRootScope();
  Output v1 = ops::Variable(scope.WithOpName("v1"), {3}, DT_FLOAT);
  Output v2 = ops::Variable(scope.WithOpName("v2"), {5, 7}, DT_FLOAT);
  Output v3 = ops::Variable(scope.WithOpName("v3"), {11, 13}, DT_FLOAT);
  Output rank = ops::Rank(scope.WithOpName("rank"), v1);
  Output shape = ops::Shape(scope.WithOpName("shape"), v2);
  Output size = ops::Size(scope.WithOpName("size"), v3);
  Output p1 = ops::Multiply(scope.WithOpName("p1"), size, rank);
  Output p2 = ops::Multiply(scope.WithOpName("p2"), p1, shape);

  GrapplerItem item;
  item.fetch.push_back("p2");
  TF_CHECK_OK(scope.ToGraphDef(&item.graph));

  ConstantFolding fold(nullptr /* cpu_device */);
  GraphDef output;
  Status status = fold.Optimize(nullptr, item, &output);
  TF_EXPECT_OK(status);

  int found = 0;
  for (const auto& node : output.node()) {
    if (node.name() == "p2") {
      ++found;
      EXPECT_EQ("Const", node.op());
      EXPECT_EQ(3, node.input_size());
      EXPECT_EQ("^v3", node.input(0));
      EXPECT_EQ("^v1", node.input(1));
      EXPECT_EQ("^v2", node.input(2));
      Tensor value;
      CHECK(value.FromProto(node.attr().at("value").tensor()));
      // rank = 1, shape = (5, 7), size = 143 = 11*13
      // p2 = (715, 1001) = (5*143, 7*143)
      EXPECT_EQ(715, value.flat<int>()(0));
      EXPECT_EQ(1001, value.flat<int>()(1));
    }
  }
  EXPECT_EQ(1, found);
}

TEST_F(ConstantFoldingTest, ShapeMaterializationEmptyFetch) {
  tensorflow::Scope scope = tensorflow::Scope::NewRootScope();
  Output v1 = ops::Variable(scope.WithOpName("v1"), {3}, DT_FLOAT);
  Output v2 = ops::Variable(scope.WithOpName("v2"), {5, 7}, DT_FLOAT);
  Output v3 = ops::Variable(scope.WithOpName("v3"), {11, 13}, DT_FLOAT);
  Output rank = ops::Rank(scope.WithOpName("rank"), v1);
  Output shape = ops::Shape(scope.WithOpName("shape"), v2);
  Output size = ops::Size(scope.WithOpName("size"), v3);
  Output p1 = ops::Multiply(scope.WithOpName("p1"), size, rank);
  Output p2 = ops::Multiply(scope.WithOpName("p2"), p1, shape);

  GrapplerItem item;
  TF_CHECK_OK(scope.ToGraphDef(&item.graph));

  ConstantFolding fold(nullptr /* cpu_device */);
  GraphDef output;
  Status status = fold.Optimize(nullptr, item, &output);
  TF_EXPECT_OK(status);

  int found = 0;
  for (const auto& node : output.node()) {
    if (node.name() == "size") {
      ++found;
      EXPECT_EQ("Const", node.op());
      EXPECT_EQ(1, node.input_size());
      EXPECT_EQ("^v3", node.input(0));
      Tensor value;
      CHECK(value.FromProto(node.attr().at("value").tensor()));
      EXPECT_EQ(11 * 13, value.flat<int>()(0));
    } else if (node.name() == "rank") {
      ++found;
      EXPECT_EQ("Const", node.op());
      EXPECT_EQ(1, node.input_size());
      EXPECT_EQ("^v1", node.input(0));
      Tensor value;
      CHECK(value.FromProto(node.attr().at("value").tensor()));
      EXPECT_EQ(1, value.flat<int>()(0));
    } else if (node.name() == "shape") {
      ++found;
      EXPECT_EQ("Const", node.op());
      EXPECT_EQ(1, node.input_size());
      EXPECT_EQ("^v2", node.input(0));
      Tensor value;
      CHECK(value.FromProto(node.attr().at("value").tensor()));
      EXPECT_EQ(5, value.flat<int>()(0));
      EXPECT_EQ(7, value.flat<int>()(1));
    }
  }
  EXPECT_EQ(3, found);
}

TEST_F(ConstantFoldingTest, ShapeMaterializationShapeN) {
  tensorflow::Scope scope = tensorflow::Scope::NewRootScope();
  Output v1 = ops::Variable(scope.WithOpName("v1"), {3, -1}, DT_FLOAT);
  Output v2 = ops::Variable(scope.WithOpName("v2"), {}, DT_FLOAT);
  Output v3 = ops::Variable(scope.WithOpName("v3"), {4, 6}, DT_FLOAT);
  auto s = ops::ShapeN(scope.WithOpName("s"), {v1, v2, v3});
  Output i1a = ops::Identity(scope.WithOpName("i1a"), s[0]);
  Output i1b = ops::Identity(scope.WithOpName("i1b"), s[0]);
  Output i2a = ops::Identity(scope.WithOpName("i2a"), s[1]);
  Output i2b = ops::Identity(scope.WithOpName("i2b"), s[1]);
  Output i2c = ops::Identity(scope.WithOpName("i2c"), s[1]);
  Output i3a = ops::Identity(scope.WithOpName("i3a"), s[2]);
  Output i3b = ops::Identity(scope.WithOpName("i3b"), s[2]);

  GrapplerItem item;
  TF_CHECK_OK(scope.ToGraphDef(&item.graph));

  ConstantFolding fold(nullptr /* cpu_device */);
  GraphDef output;
  Status status = fold.Optimize(nullptr, item, &output);
  TF_EXPECT_OK(status);
  int found = 0;
  for (const auto& node : output.node()) {
    EXPECT_NE(AddPrefixToNodeName("s-matshapes-0", kConstantFoldingConst),
              node.name());
    EXPECT_NE(AddPrefixToNodeName("s-matshapes-1", kConstantFoldingConst),
              node.name());
    if (node.name() == "i1a" || node.name() == "i1b") {
      ++found;
      EXPECT_EQ("s", node.input(0));
    }
    if (node.name() == "i2a" || node.name() == "i2b" || node.name() == "i2c") {
      ++found;
      EXPECT_EQ("s:1", node.input(0));
    }
    if (node.name() == "i3a" || node.name() == "i3b") {
      ++found;
      EXPECT_EQ(AddPrefixToNodeName("s-matshapes-2", kConstantFoldingConst),
                node.input(0));
    }
    if (node.name() == "s") {
      ++found;
      EXPECT_EQ("ShapeN", node.op());
      EXPECT_EQ("v1", node.input(0));
      EXPECT_EQ("v2", node.input(1));
      EXPECT_EQ("v3", node.input(2));
    }
    if (node.name() ==
        AddPrefixToNodeName("s-matshapes-2", kConstantFoldingConst)) {
      ++found;
      EXPECT_EQ("Const", node.op());
      EXPECT_EQ("^s", node.input(0));
      Tensor value;
      CHECK(value.FromProto(node.attr().at("value").tensor()));
      EXPECT_EQ(4, value.flat<int>()(0));
      EXPECT_EQ(6, value.flat<int>()(1));
    }
  }
  EXPECT_EQ(9, found);
}

TEST_F(ConstantFoldingTest, SwitchNodesEmptyFetch) {
  tensorflow::Scope scope = tensorflow::Scope::NewRootScope();
  ops::Variable v_in(scope.WithOpName("v_in"), {3}, DT_FLOAT);
  ops::Variable v_ctrl(scope.WithOpName("v_ctrl"), {}, DT_BOOL);
  ops::Switch s1(scope.WithOpName("switch"), v_in, v_ctrl);
  ops::Rank rank(scope.WithOpName("rank"), s1.output_false);
  ops::Identity i(scope.WithOpName("i"), s1.output_true);
  ops::Size size(scope.WithOpName("size"), i);
  ops::Square p1(scope.WithOpName("p1"), rank);
  ops::Square p2(scope.WithOpName("p2"), size);
  ops::Merge m(scope.WithOpName("m"), {p1.y, p2.y});

  Output predicate =
      ops::Const(scope.WithOpName("false"), false, TensorShape({}));
  Output constant =
      ops::Const(scope.WithOpName("constant"), 1.0f, TensorShape({1}));
  ops::Switch s2(scope.WithOpName("switch2"), constant, predicate);
  ops::Identity statically_known(scope.WithOpName("i2"), s2.output_false);
  ops::Identity never_generated(scope.WithOpName("i3"), s2.output_true);
  ops::Merge m2(scope.WithOpName("m2"),
                {statically_known.output, never_generated.output});

  GrapplerItem item;
  TF_CHECK_OK(scope.ToGraphDef(&item.graph));

  ConstantFolding fold(nullptr /* cpu_device */);
  GraphDef output;
  Status status = fold.Optimize(nullptr, item, &output);
  TF_EXPECT_OK(status);

  std::set<string> present_nodes = {"v_in",     "v_ctrl",
                                    "switch",   "i",
                                    "p1",       "p2",
                                    "m",        "false",
                                    "constant", "switch2",
                                    "i2",       "i3",
                                    "m2",       "ConstantFoldingCtrl/switch_0",
                                    "rank",     "size"};
  std::set<string> not_present_nodes = {"ConstantFolding/switch2-0"};
  EXPECT_EQ(present_nodes.size(), output.node_size());
  int found = 0;
  for (const auto& node : output.node()) {
    EXPECT_TRUE(present_nodes.find(node.name()) != present_nodes.end());
    EXPECT_TRUE(not_present_nodes.find(node.name()) == not_present_nodes.end());
    present_nodes.erase(node.name());
    not_present_nodes.erase(node.name());
    if (node.name() == "rank") {
      ++found;
      EXPECT_EQ("Const", node.op());
      EXPECT_EQ(1, node.input_size());
      EXPECT_EQ("^ConstantFoldingCtrl/switch_0", node.input(0));
    }
    if (node.name() == "size") {
      ++found;
      EXPECT_EQ("Const", node.op());
      EXPECT_EQ(1, node.input_size());
      EXPECT_EQ("^i", node.input(0));
    }
    if (node.name() == "i2") {
      ++found;
      EXPECT_EQ("Const", node.op());
      EXPECT_EQ(0, node.input_size());
    }
    if (node.name() == "i3") {
      ++found;
      EXPECT_EQ("Identity", node.op());
      EXPECT_EQ(1, node.input_size());
      EXPECT_EQ("switch2:1", node.input(0));
    }
  }
  EXPECT_EQ(4, found);
}

TEST_F(ConstantFoldingTest, SwitchNodes) {
  tensorflow::Scope scope = tensorflow::Scope::NewRootScope();
  ops::Variable v_in(scope.WithOpName("v_in"), {3}, DT_FLOAT);
  ops::Variable v_ctrl(scope.WithOpName("v_ctrl"), {}, DT_BOOL);
  ops::Switch s1(scope.WithOpName("switch"), v_in, v_ctrl);
  ops::Rank rank(scope.WithOpName("rank"), s1.output_false);
  ops::Identity i(scope.WithOpName("i"), s1.output_true);
  ops::Size size(scope.WithOpName("size"), i);
  ops::Square p1(scope.WithOpName("p1"), rank);
  ops::Square p2(scope.WithOpName("p2"), size);
  ops::Merge m(scope.WithOpName("m"), {p1.y, p2.y});

  Output predicate =
      ops::Const(scope.WithOpName("false"), false, TensorShape({}));
  Output constant =
      ops::Const(scope.WithOpName("constant"), 1.0f, TensorShape({1}));
  ops::Switch s2(scope.WithOpName("switch2"), constant, predicate);
  ops::Identity statically_known(scope.WithOpName("i2"), s2.output_false);
  ops::Identity never_generated(scope.WithOpName("i3"), s2.output_true);
  ops::Merge m2(scope.WithOpName("m2"),
                {statically_known.output, never_generated.output});

  GrapplerItem item;
  item.fetch.push_back("m");
  item.fetch.push_back("m2");

  TF_CHECK_OK(scope.ToGraphDef(&item.graph));

  ConstantFolding fold(nullptr /* cpu_device */);
  GraphDef output;
  Status status = fold.Optimize(nullptr, item, &output);
  TF_EXPECT_OK(status);
  std::set<string> present_nodes = {"v_in",     "v_ctrl",
                                    "switch",   "i",
                                    "p1",       "p2",
                                    "m",        "false",
                                    "constant", "switch2",
                                    "i2",       "i3",
                                    "m2",       "ConstantFoldingCtrl/switch_0"};
  std::set<string> not_present_nodes = {"rank", "size",
                                        "ConstantFolding/switch2-0"};
  EXPECT_EQ(present_nodes.size(), output.node_size());

  int found = 0;
  for (const auto& node : output.node()) {
    EXPECT_TRUE(present_nodes.find(node.name()) != present_nodes.end());
    EXPECT_TRUE(not_present_nodes.find(node.name()) == not_present_nodes.end());
    present_nodes.erase(node.name());
    not_present_nodes.erase(node.name());
    if (node.name() == "i2") {
      ++found;
      EXPECT_EQ("Const", node.op());
      EXPECT_EQ(0, node.input_size());
    }
    if (node.name() == "i3") {
      ++found;
      EXPECT_EQ("Identity", node.op());
      EXPECT_EQ(1, node.input_size());
      EXPECT_EQ("switch2:1", node.input(0));
    }
  }
  EXPECT_EQ(2, found);
}

TEST_F(ConstantFoldingTest, MergeNodes) {
  tensorflow::Scope scope = tensorflow::Scope::NewRootScope();

  Output x =
      ops::RandomNormal(scope.WithOpName("x"), {3, 5}, DataType::DT_FLOAT);
  Output y =
      ops::RandomNormal(scope.WithOpName("y"), {3, 5}, DataType::DT_FLOAT);
  Output const1 =
      ops::Const(scope.WithOpName("const1").WithControlDependencies(x), 2.7f,
                 TensorShape({3, 5}));
  Output const2 =
      ops::Const(scope.WithOpName("const2"), 3.14f, TensorShape({3, 5}));
  Output const3 =
      ops::Const(scope.WithOpName("const3").WithControlDependencies(x), 3.14f,
                 TensorShape({3, 5}));

  // Create 3 merge nodes: m1 is foldable, m2 and m3 aren't.
  ops::Merge m1(scope.WithOpName("m1"), {x, const1, const2});
  ops::Merge m2(scope.WithOpName("m2"), {const1, const3});
  ops::Merge m3(scope.WithOpName("m3"), {x, y});

  ops::Identity out1(scope.WithOpName("out1"), m1.output);
  ops::Identity idx1(scope.WithOpName("idx1"), m1.value_index);
  ops::Identity out2(scope.WithOpName("out2"), m2.output);
  ops::Identity idx2(scope.WithOpName("idx2"), m2.value_index);
  ops::Identity out3(scope.WithOpName("out3"), m3.output);
  ops::Identity idx3(scope.WithOpName("idx3"), m3.value_index);

  GrapplerItem item;
  item.fetch = {"out1", "idx1", "out2", "idx2", "out3", "idx3"};
  TF_CHECK_OK(scope.ToGraphDef(&item.graph));

  ConstantFolding fold(nullptr /* cpu_device */);
  GraphDef output;
  Status status = fold.Optimize(nullptr, item, &output);
  TF_EXPECT_OK(status);

  int found_nodes = 0;
  for (const auto& node : output.node()) {
    if (node.name() == "out1") {
      EXPECT_EQ(1, node.input_size());
      EXPECT_EQ("^m1", node.input(0));
      ++found_nodes;
    } else if (node.name() == "idx1") {
      EXPECT_EQ(1, node.input_size());
      EXPECT_EQ("^m1", node.input(0));
      ++found_nodes;
    } else if (node.name() == "ConstantFolding/m1") {
      EXPECT_EQ("Const", node.op());
      EXPECT_EQ(1, node.input_size());
      EXPECT_EQ("^m1", node.input(0));
      ++found_nodes;
    } else if (node.name() == "ConstantFolding/m1_index") {
      EXPECT_EQ("Const", node.op());
      EXPECT_EQ(1, node.input_size());
      EXPECT_EQ("^m1", node.input(0));
      ++found_nodes;
    } else if (node.name() == "out2") {
      EXPECT_EQ(1, node.input_size());
      EXPECT_EQ("m2", node.input(0));
      ++found_nodes;
    } else if (node.name() == "idx2") {
      EXPECT_EQ(1, node.input_size());
      EXPECT_EQ("m2:1", node.input(0));
      ++found_nodes;
    } else if (node.name() == "out3") {
      EXPECT_EQ(1, node.input_size());
      EXPECT_EQ("m3", node.input(0));
      ++found_nodes;
    } else if (node.name() == "idx3") {
      EXPECT_EQ(1, node.input_size());
      EXPECT_EQ("m3:1", node.input(0));
      ++found_nodes;
    }
  }
  // Make sure the graph contains all the nodes we're expecting.
  EXPECT_EQ(6, found_nodes);

  std::vector<string> fetch = {"out1", "idx1"};
  auto tensors = EvaluateNodes(output, fetch);
  EXPECT_EQ(2, tensors.size());
  const Tensor& out_value = tensors[0];
  EXPECT_EQ(3 * 5, out_value.NumElements());
  for (int i = 0; i < 3 * 5; ++i) {
    EXPECT_EQ(3.14f, out_value.flat<float>()(i));
  }
  const Tensor& out_idx = tensors[1];
  EXPECT_EQ(1, out_idx.NumElements());
  EXPECT_EQ(2, out_idx.flat<int32>()(0));
}

TEST_F(ConstantFoldingTest, NoOpReduction) {
  // Build a simple graph with a reduction that can be reduced to the identity.
  tensorflow::Scope scope = tensorflow::Scope::NewRootScope();

  Output v = ops::Variable(scope.WithOpName("v"), {3, 5, 7}, DT_FLOAT);
  Output c =
      ops::Const(scope.WithOpName("c").WithControlDependencies(v), 0, {0});
  Output i = ops::Identity(scope.WithOpName("i"), c);
  Output p = ops::Prod(scope.WithOpName("p"), v, i);
  Output s = ops::Square(scope.WithOpName("s"), p);

  GrapplerItem item;
  item.fetch.push_back("s");
  TF_CHECK_OK(scope.ToGraphDef(&item.graph));

  ConstantFolding fold(nullptr /* cpu_device */);
  GraphDef output;
  Status status = fold.Optimize(nullptr, item, &output);
  TF_EXPECT_OK(status);

  bool found = false;
  for (const auto& node : output.node()) {
    if (node.name() == "p") {
      found = true;
      EXPECT_EQ("Identity", node.op());
      EXPECT_EQ(2, node.input_size());
      EXPECT_EQ("v", node.input(0));
      EXPECT_EQ("^i", node.input(1));
    }
  }
  EXPECT_TRUE(found);
}

TEST_F(ConstantFoldingTest, NoOpReshape) {
  // Build a simple graph with a reshape that can be reduced to the identity.
  tensorflow::Scope scope = tensorflow::Scope::NewRootScope();

  // A reshape than can be optimized
  Output d1 = ops::Const(scope.WithOpName("d1"), 3.14f, {17});
  Output v1 = ops::Variable(scope.WithOpName("v1"), {17}, DT_FLOAT);
  Output c1 =
      ops::Const(scope.WithOpName("c1").WithControlDependencies(v1), 17, {1});
  Output i1 = ops::Identity(scope.WithOpName("i1"), c1);
  Output r1 =
      ops::Reshape(scope.WithOpName("r1").WithControlDependencies(d1), v1, i1);
  Output s1 = ops::Square(scope.WithOpName("s1"), r1);

  // A multi dimensional reshape than can be optimized
  Output v3 = ops::Variable(scope.WithOpName("v3"), {5, 5, 5}, DT_FLOAT);
  Output c3 =
      ops::Const(scope.WithOpName("c3").WithControlDependencies(v3), 5, {3});
  Output i3 = ops::Identity(scope.WithOpName("i3"), c3);
  Output r3 = ops::Reshape(scope.WithOpName("r3"), v3, i3);
  Output s3 = ops::Square(scope.WithOpName("s3"), r3);

  // A multi dimensional partially defined reshape than can be optimized
  Output v4 = ops::Variable(scope.WithOpName("v4"), {5, 5, 5}, DT_FLOAT);
  Output c4 = ops::Const(scope.WithOpName("c4").WithControlDependencies(v4),
                         {5, -1, 5}, {3});
  Output i4 = ops::Identity(scope.WithOpName("i4"), c4);
  Output r4 = ops::Reshape(scope.WithOpName("r4"), v4, i4);
  Output s4 = ops::Square(scope.WithOpName("s4"), r4);

  // A reshape that can't be optimized
  Output v2 = ops::Variable(scope.WithOpName("v2"), {17, 1}, DT_FLOAT);
  Output c2 =
      ops::Const(scope.WithOpName("c2").WithControlDependencies(v2), 17, {1});
  Output r2 = ops::Reshape(scope.WithOpName("r2"), v2, c2);
  Output s2 = ops::Square(scope.WithOpName("s2"), r2);

  GrapplerItem item;
  item.fetch = {"s1", "s2", "s3", "s4"};
  TF_CHECK_OK(scope.ToGraphDef(&item.graph));

  ConstantFolding fold(nullptr /* cpu_device */);
  GraphDef output;
  Status status = fold.Optimize(nullptr, item, &output);
  TF_EXPECT_OK(status);

  int found = 0;
  for (const auto& node : output.node()) {
    if (node.name() == "r1") {
      ++found;
      EXPECT_EQ("Identity", node.op());
      ASSERT_EQ(3, node.input_size());
      EXPECT_EQ("v1", node.input(0));
      EXPECT_EQ("^i1", node.input(1));
      EXPECT_EQ("^d1", node.input(2));
    } else if (node.name() == "r3") {
      ++found;
      EXPECT_EQ("Identity", node.op());
      ASSERT_EQ(2, node.input_size());
      EXPECT_EQ("v3", node.input(0));
      EXPECT_EQ("^i3", node.input(1));
    } else if (node.name() == "r4") {
      ++found;
      EXPECT_EQ("Identity", node.op());
      ASSERT_EQ(2, node.input_size());
      EXPECT_EQ("v4", node.input(0));
      EXPECT_EQ("^i4", node.input(1));
    } else if (node.name() == "r2") {
      ++found;
      EXPECT_EQ("Reshape", node.op());
      ASSERT_EQ(2, node.input_size());
      EXPECT_EQ("v2", node.input(0));
      EXPECT_EQ("c2", node.input(1));
    }
  }
  EXPECT_EQ(4, found);
}

TEST_F(ConstantFoldingTest, Packing) {
  // Build a simple graph with a large constant that can be folded.
  tensorflow::Scope scope = tensorflow::Scope::NewRootScope();
  Output c = ops::Const(scope.WithOpName("c"), 3.14f, {1000});
  Output i1 = ops::Identity(scope.WithOpName("i1"), c);
  Output i2 = ops::Identity(scope.WithOpName("i2"), c);

  GrapplerItem item;
  TF_CHECK_OK(scope.ToGraphDef(&item.graph));

  ConstantFolding fold(nullptr /* cpu_device */);
  GraphDef output;
  Status status = fold.Optimize(nullptr, item, &output);
  TF_EXPECT_OK(status);

  // Make sure that the representation of the folded constant is space
  // efficient: in particular, the whole message should be smaller than 8k (the
  // size needed to naively encode 1000 floats folded twice).
  EXPECT_GT(8000, output.ByteSizeLong());
}

TEST_F(ConstantFoldingTest, MaterializeBroadcastGradientArgs) {
  tensorflow::Scope s = tensorflow::Scope::NewRootScope();
  Output a =
      ops::Placeholder(s.WithOpName("a"), DT_FLOAT,
                       ops::Placeholder::Shape(PartialTensorShape({-1, -1})));
  Output b = ops::Square(s.WithOpName("b"), a);
  Output c = ops::Mul(s.WithOpName("c"), a, b);
  Output d = ops::Shape(s.WithOpName("d"), a);
  Output e = ops::Shape(s.WithOpName("e"), b);

  auto f = ops::internal::BroadcastGradientArgs(s.WithOpName("f"), d, e);
  Output o1 = ops::Identity(s.WithOpName("o1"), f.r0);
  Output o2 = ops::Identity(s.WithOpName("o2"), f.r1);

  Output g = ops::Placeholder(s.WithOpName("g"), DT_FLOAT,
                              ops::Placeholder::Shape(PartialTensorShape({1})));
  Output h = ops::Shape(s.WithOpName("h"), g);
  auto i = ops::internal::BroadcastGradientArgs(s.WithOpName("i"), d, h);
  Output p1 = ops::Identity(s.WithOpName("p1"), i.r0);
  Output p2 = ops::Identity(s.WithOpName("p2"), i.r1);

  GrapplerItem item;
  TF_CHECK_OK(s.ToGraphDef(&item.graph));

  ConstantFolding fold(RewriterConfig::AGGRESSIVE, nullptr /* cpu_device */);
  GraphDef output;
  Status status = fold.Optimize(nullptr, item, &output);
  TF_EXPECT_OK(status);

  // Run a second time to make sure the optimization is idempotent.
  item.graph.Swap(&output);
  status = fold.Optimize(nullptr, item, &output);
  TF_EXPECT_OK(status);

  int found = 0;
  for (const auto& node : output.node()) {
    if (node.name() == "o1") {
      ++found;
      EXPECT_EQ(1, node.input_size());
      EXPECT_EQ("ConstantFolding/f-bcastargs-0", node.input(0));
    } else if (node.name() == "o2") {
      ++found;
      EXPECT_EQ(1, node.input_size());
      EXPECT_EQ("ConstantFolding/f-bcastargs-1", node.input(0));
    } else if (node.name() == "ConstantFolding/f-bcastargs-0") {
      ++found;
      EXPECT_EQ("Const", node.op());
      EXPECT_EQ(1, node.input_size());
      EXPECT_EQ("^f", node.input(0));
      EXPECT_EQ(0, TensorShape(node.attr().at("value").tensor().tensor_shape())
                       .num_elements());
    } else if (node.name() == "ConstantFolding/f-bcastargs-1") {
      ++found;
      EXPECT_EQ("Const", node.op());
      EXPECT_EQ(1, node.input_size());
      EXPECT_EQ("^f", node.input(0));
      EXPECT_EQ(0, TensorShape(node.attr().at("value").tensor().tensor_shape())
                       .num_elements());
    } else if (node.name() == "p1") {
      ++found;
      EXPECT_EQ(1, node.input_size());
      EXPECT_EQ("i", node.input(0));
    } else if (node.name() == "p2") {
      ++found;
      EXPECT_EQ(1, node.input_size());
      EXPECT_EQ("i:1", node.input(0));
    }
  }
  EXPECT_EQ(6, found);
}

TEST_F(ConstantFoldingTest, MaterializeReductionIndices) {
  tensorflow::Scope s = tensorflow::Scope::NewRootScope();
  Output input =
      ops::Placeholder(s.WithOpName("input"), DT_FLOAT,
                       ops::Placeholder::Shape(PartialTensorShape({-1, -1})));
  Output indices = ops::Placeholder(s.WithOpName("indices"), DT_INT32);
  Output sum = ops::Sum(s.WithOpName("sum"), input, indices);
  Output size = ops::Const(s.WithOpName("size"), 1, {1});
  Output reshape = ops::Reshape(s.WithOpName("reshape"), sum, size);

  GrapplerItem item;
  TF_CHECK_OK(s.ToGraphDef(&item.graph));
  item.fetch.push_back("reshape");

  ConstantFolding fold(RewriterConfig::AGGRESSIVE, nullptr /* cpu_device */);
  GraphDef output;
  Status status = fold.Optimize(nullptr, item, &output);
  TF_EXPECT_OK(status);

  // Run a second time to make sure the optimization is idempotent.
  item.graph.Swap(&output);
  status = fold.Optimize(nullptr, item, &output);
  TF_EXPECT_OK(status);

  int found = 0;
  for (const auto& node : output.node()) {
    if (node.name() == "ConstantFolding/sum-reduction_indices") {
      ++found;
      EXPECT_EQ("Const", node.op());
      EXPECT_EQ("^indices", node.input(0));
      EXPECT_EQ(2, TensorShape(node.attr().at("value").tensor().tensor_shape())
                       .num_elements());
    } else if (node.name() == "sum") {
      ++found;
      EXPECT_EQ("ConstantFolding/sum-reduction_indices", node.input(1));
    } else if (node.name() == "indices") {
      ++found;
    }
  }
  EXPECT_EQ(3, found);
}

}  // namespace
}  // namespace grappler
}  // namespace tensorflow

//  LocalWords:  NewRootScope


text:
package beaconing

import (
	"context"
	"crypto"
	"crypto/ecdsa"
	"crypto/elliptic"
	"crypto/rand"
	"errors"
	"fmt"
	"hash"
	"net"
	"sync"
	"testing"
	"time"

	"github.com/golang/mock/gomock"
	"github.com/stretchr/testify/assert"
	"github.com/stretchr/testify/require"

	"github.com/scionproto/scion/go/cs/beacon"
	"github.com/scionproto/scion/go/cs/beaconing/mock_beaconing"
	"github.com/scionproto/scion/go/cs/ifstate"
	"github.com/scionproto/scion/go/lib/addr"
	"github.com/scionproto/scion/go/lib/common"
	"github.com/scionproto/scion/go/lib/ctrl/seg"
	"github.com/scionproto/scion/go/lib/infra/modules/itopo/itopotest"
	"github.com/scionproto/scion/go/lib/infra/modules/seghandler"
	"github.com/scionproto/scion/go/lib/scrypto"
	"github.com/scionproto/scion/go/lib/scrypto/cppki"
	"github.com/scionproto/scion/go/lib/scrypto/signed"
	"github.com/scionproto/scion/go/lib/slayers/path/scion"
	"github.com/scionproto/scion/go/lib/snet"
	"github.com/scionproto/scion/go/lib/snet/addrutil"
	"github.com/scionproto/scion/go/lib/xtest/graph"
	"github.com/scionproto/scion/go/pkg/trust"
)

func TestRegistrarRun(t *testing.T) {
	priv, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader)
	require.NoError(t, err)
	pub := priv.Public()

	testsLocal := []struct {
		name          string
		segType       seg.Type
		fn            string
		beacons       [][]common.IFIDType
		inactivePeers map[common.IFIDType]bool
	}{
		{
			name:    "Core segment",
			segType: seg.TypeCore,
			fn:      topoCore,
			beacons: [][]common.IFIDType{
				{graph.If_120_A_110_X},
				{graph.If_130_B_120_A, graph.If_120_A_110_X},
			},
		},
		{
			name:          "Up segment",
			segType:       seg.TypeUp,
			fn:            topoNonCore,
			inactivePeers: map[common.IFIDType]bool{graph.If_111_C_121_X: true},
			beacons: [][]common.IFIDType{
				{graph.If_120_X_111_B},
				{graph.If_130_B_120_A, graph.If_120_X_111_B},
			},
		},
	}
	for _, test := range testsLocal {
		t.Run(test.name, func(t *testing.T) {
			mctrl := gomock.NewController(t)
			defer mctrl.Finish()
			topoProvider := itopotest.TopoProviderFromFile(t, test.fn)
			intfs := ifstate.NewInterfaces(topoProvider.Get().IFInfoMap(), ifstate.Config{})
			segProvider := mock_beaconing.NewMockSegmentProvider(mctrl)
			segStore := mock_beaconing.NewMockSegmentStore(mctrl)

			r := WriteScheduler{
				Writer: &LocalWriter{
					Extender: &DefaultExtender{
						IA:         topoProvider.Get().IA(),
						MTU:        topoProvider.Get().MTU(),
						Signer:     testSigner(t, priv, topoProvider.Get().IA()),
						Intfs:      intfs,
						MAC:        macFactory,
						MaxExpTime: func() uint8 { return uint8(beacon.DefaultMaxExpTime) },
						StaticInfo: func() *StaticInfoCfg { return nil },
					},
					Intfs: intfs,
					Store: segStore,
					Type:  test.segType,
				},
				Intfs:    intfs,
				Tick:     NewTick(time.Hour),
				Provider: segProvider,
				Type:     test.segType,
			}
			g := graph.NewDefaultGraph(mctrl)
			segProvider.EXPECT().SegmentsToRegister(gomock.Any(), test.segType).DoAndReturn(
				func(_, _ interface{}) (<-chan beacon.BeaconOrErr, error) {
					res := make(chan beacon.BeaconOrErr, len(test.beacons))
					for _, desc := range test.beacons {
						res <- testBeaconOrErr(g, desc)
					}
					close(res)
					return res, nil
				})
			var stored []*seg.Meta
			segStore.EXPECT().StoreSegs(gomock.Any(), gomock.Any()).DoAndReturn(
				func(_ context.Context, segs []*seg.Meta) (seghandler.SegStats, error) {
					for _, s := range segs {
						stored = append(stored, s)
					}
					return seghandler.SegStats{}, nil
				},
			)

			r.Run(context.Background())
			assert.Len(t, stored, len(test.beacons))
			for _, s := range stored {
				assert.NoError(t, s.Segment.Validate(seg.ValidateSegment))
				assert.NoError(t, s.Segment.VerifyASEntry(context.Background(),
					segVerifier{pubKey: pub}, s.Segment.MaxIdx()))
				assert.Equal(t, test.segType, s.Type)
			}
			// The second run should not do anything, since the period has not passed.
			r.Run(context.Background())
		})
	}
	testsRemote := []struct {
		name          string
		segType       seg.Type
		fn            string
		beacons       [][]common.IFIDType
		inactivePeers map[common.IFIDType]bool
	}{
		{
			name:          "Down segment",
			segType:       seg.TypeDown,
			fn:            topoNonCore,
			inactivePeers: map[common.IFIDType]bool{graph.If_111_C_121_X: true},
			beacons: [][]common.IFIDType{
				{graph.If_120_X_111_B},
				{graph.If_130_B_120_A, graph.If_120_X_111_B},
			},
		},
	}
	for _, test := range testsRemote {
		t.Run(test.name, func(t *testing.T) {
			mctrl := gomock.NewController(t)
			defer mctrl.Finish()
			topoProvider := itopotest.TopoProviderFromFile(t, test.fn)
			intfs := ifstate.NewInterfaces(topoProvider.Get().IFInfoMap(), ifstate.Config{})
			segProvider := mock_beaconing.NewMockSegmentProvider(mctrl)
			rpc := mock_beaconing.NewMockRPC(mctrl)

			r := WriteScheduler{
				Writer: &RemoteWriter{
					Extender: &DefaultExtender{
						IA:         topoProvider.Get().IA(),
						MTU:        topoProvider.Get().MTU(),
						Signer:     testSigner(t, priv, topoProvider.Get().IA()),
						Intfs:      intfs,
						MAC:        macFactory,
						MaxExpTime: func() uint8 { return uint8(beacon.DefaultMaxExpTime) },
						StaticInfo: func() *StaticInfoCfg { return nil },
					},
					Pather: addrutil.Pather{
						UnderlayNextHop: func(ifID uint16) (*net.UDPAddr, bool) {
							return topoProvider.Get().UnderlayNextHop2(common.IFIDType(ifID))
						},
					},
					RPC:   rpc,
					Type:  test.segType,
					Intfs: intfs,
				},
				Intfs:    intfs,
				Tick:     NewTick(time.Hour),
				Provider: segProvider,
				Type:     test.segType,
			}
			g := graph.NewDefaultGraph(mctrl)
			segProvider.EXPECT().SegmentsToRegister(gomock.Any(), test.segType).DoAndReturn(
				func(_, _ interface{}) (<-chan beacon.BeaconOrErr, error) {
					res := make(chan beacon.BeaconOrErr, len(test.beacons))
					for _, desc := range test.beacons {
						res <- testBeaconOrErr(g, desc)
					}
					close(res)
					return res, nil
				})
			type regMsg struct {
				Meta seg.Meta
				Addr *snet.SVCAddr
			}
			segMu := sync.Mutex{}
			var sent []regMsg
			// Collect the segments that are sent on the messenger.

			rpc.EXPECT().RegisterSegment(gomock.Any(), gomock.Any(),
				gomock.Any()).Times(len(test.beacons)).DoAndReturn(
				func(_ context.Context, meta seg.Meta, remote net.Addr) error {
					segMu.Lock()
					defer segMu.Unlock()
					sent = append(sent, regMsg{
						Meta: meta,
						Addr: remote.(*snet.SVCAddr),
					})
					return nil
				},
			)
			r.Run(context.Background())
			require.Len(t, sent, len(test.beacons))
			for segIdx, s := range sent {
				t.Run(fmt.Sprintf("seg idx %d", segIdx), func(t *testing.T) {
					pseg := s.Meta.Segment

					assert.NoError(t, pseg.Validate(seg.ValidateSegment))
					assert.NoError(t, pseg.VerifyASEntry(context.Background(),
						segVerifier{pubKey: pub}, pseg.MaxIdx()))

					assert.Equal(t, pseg.FirstIA(), s.Addr.IA)
					assert.Equal(t, addr.SvcCS, s.Addr.SVC)

					var path scion.Decoded
					if assert.NoError(t, path.DecodeFromBytes(s.Addr.Path.Raw)) {
						pathHopField := path.HopFields[0]

						segHopField := pseg.ASEntries[pseg.MaxIdx()].HopEntry.HopField
						assert.Equal(t, []byte(pathHopField.Mac), segHopField.MAC)
						assert.Equal(t, pathHopField.ConsIngress, segHopField.ConsIngress)
						assert.Equal(t, pathHopField.ConsEgress, segHopField.ConsEgress)

						nextHop := common.IFIDType(pathHopField.ConsIngress)
						a := topoProvider.Get().IFInfoMap()[nextHop].InternalAddr
						assert.Equal(t, a, s.Addr.NextHop)
					}
				})
			}
			// The second run should not do anything, since the period has not passed.
			r.Run(context.Background())
		})
	}
	t.Run("Run drains the channel", func(t *testing.T) {
		mctrl := gomock.NewController(t)
		defer mctrl.Finish()
		topoProvider := itopotest.TopoProviderFromFile(t, topoCore)
		intfs := ifstate.NewInterfaces(topoProvider.Get().IFInfoMap(), ifstate.Config{})
		segProvider := mock_beaconing.NewMockSegmentProvider(mctrl)

		r := WriteScheduler{
			Writer: &LocalWriter{
				Extender: &DefaultExtender{
					IA:         topoProvider.Get().IA(),
					MTU:        topoProvider.Get().MTU(),
					Signer:     testSigner(t, priv, topoProvider.Get().IA()),
					Intfs:      intfs,
					MAC:        macFactory,
					MaxExpTime: func() uint8 { return uint8(beacon.DefaultMaxExpTime) },
					StaticInfo: func() *StaticInfoCfg { return nil },
				},
				Intfs: intfs,
				Type:  seg.TypeCore,
			},
			Intfs:    intfs,
			Tick:     NewTick(time.Hour),
			Provider: segProvider,
			Type:     seg.TypeCore,
		}
		res := make(chan beacon.BeaconOrErr, 3)
		segProvider.EXPECT().SegmentsToRegister(gomock.Any(), seg.TypeCore).DoAndReturn(
			func(_, _ interface{}) (<-chan beacon.BeaconOrErr, error) {
				for i := 0; i < 3; i++ {
					res <- beacon.BeaconOrErr{Err: errors.New("Invalid beacon")}
				}
				close(res)
				return res, nil
			})
		r.Run(context.Background())
		select {
		case b := <-res:
			assert.Zero(t, b)
		default:
			t.Fatal("Must not block")
		}
	})
	t.Run("Faulty beacons are not sent", func(t *testing.T) {
		mctrl := gomock.NewController(t)
		defer mctrl.Finish()
		topoProvider := itopotest.TopoProviderFromFile(t, topoNonCore)
		intfs := ifstate.NewInterfaces(topoProvider.Get().IFInfoMap(), ifstate.Config{})
		segProvider := mock_beaconing.NewMockSegmentProvider(mctrl)
		rpc := mock_beaconing.NewMockRPC(mctrl)

		r := WriteScheduler{
			Writer: &RemoteWriter{
				Extender: &DefaultExtender{
					IA:         topoProvider.Get().IA(),
					MTU:        topoProvider.Get().MTU(),
					Signer:     testSigner(t, priv, topoProvider.Get().IA()),
					Intfs:      intfs,
					MAC:        macFactory,
					MaxExpTime: func() uint8 { return uint8(beacon.DefaultMaxExpTime) },
					StaticInfo: func() *StaticInfoCfg { return nil },
				},
				Pather: addrutil.Pather{
					UnderlayNextHop: func(ifID uint16) (*net.UDPAddr, bool) {
						return topoProvider.Get().UnderlayNextHop2(common.IFIDType(ifID))
					},
				},
				RPC:   rpc,
				Intfs: intfs,
				Type:  seg.TypeDown,
			},
			Intfs:    intfs,
			Tick:     NewTick(time.Hour),
			Provider: segProvider,
			Type:     seg.TypeDown,
		}
		g := graph.NewDefaultGraph(mctrl)
		require.NoError(t, err)
		segProvider.EXPECT().SegmentsToRegister(gomock.Any(),
			seg.TypeDown).DoAndReturn(
			func(_, _ interface{}) (<-chan beacon.BeaconOrErr, error) {
				res := make(chan beacon.BeaconOrErr, 1)
				b := testBeaconOrErr(g, []common.IFIDType{graph.If_120_X_111_B})
				b.Beacon.InIfId = 10
				res <- b
				close(res)
				return res, nil
			})
		r.Run(context.Background())
	})
}

func testBeaconOrErr(g *graph.Graph, desc []common.IFIDType) beacon.BeaconOrErr {
	bseg := g.Beacon(desc)
	asEntry := bseg.ASEntries[bseg.MaxIdx()]
	bseg.ASEntries = bseg.ASEntries[:len(bseg.ASEntries)-1]

	return beacon.BeaconOrErr{
		Beacon: beacon.Beacon{
			InIfId:  common.IFIDType(asEntry.HopEntry.HopField.ConsIngress),
			Segment: bseg,
		},
	}
}

func testSigner(t *testing.T, priv crypto.Signer, ia addr.IA) seg.Signer {
	return trust.Signer{
		PrivateKey: priv,
		Algorithm:  signed.ECDSAWithSHA512,
		IA:         ia,
		TRCID: cppki.TRCID{
			ISD:    ia.I,
			Base:   1,
			Serial: 21,
		},
		SubjectKeyID: []byte("skid"),
		Expiration:   time.Now().Add(time.Hour),
	}
}

var macFactory = func() hash.Hash {
	mac, err := scrypto.InitMac(make([]byte, 16))
	// This can only happen if the library is messed up badly.
	if err != nil {
		panic(err)
	}
	return mac
}

redpajama_set_name: RedPajamaGithub


text:
package com.amazonaws.services.rds.model.transform;

import java.util.Map;
import java.util.Map.Entry;

import javax.xml.stream.events.XMLEvent;

import com.amazonaws.services.rds.model.*;
import com.amazonaws.transform.Unmarshaller;
import com.amazonaws.transform.MapEntry;
import com.amazonaws.transform.StaxUnmarshallerContext;
import com.amazonaws.transform.SimpleTypeStaxUnmarshallers.*;

/**
 * Reserved D B Instance StAX Unmarshaller
 */
public class ReservedDBInstanceStaxUnmarshaller implements Unmarshaller<ReservedDBInstance, StaxUnmarshallerContext> {

    public ReservedDBInstance unmarshall(StaxUnmarshallerContext context) throws Exception {
        ReservedDBInstance reservedDBInstance = new ReservedDBInstance();
        int originalDepth = context.getCurrentDepth();
        int targetDepth = originalDepth + 1;

        if (context.isStartOfDocument()) targetDepth += 2;

        if (context.isStartOfDocument()) targetDepth++;

        while (true) {
            XMLEvent xmlEvent = context.nextEvent();
            if (xmlEvent.isEndDocument()) return reservedDBInstance;

            if (xmlEvent.isAttribute() || xmlEvent.isStartElement()) {
                if (context.testExpression("ReservedDBInstanceId", targetDepth)) {
                    reservedDBInstance.setReservedDBInstanceId(StringStaxUnmarshaller.getInstance().unmarshall(context));
                    continue;
                }
                if (context.testExpression("ReservedDBInstancesOfferingId", targetDepth)) {
                    reservedDBInstance.setReservedDBInstancesOfferingId(StringStaxUnmarshaller.getInstance().unmarshall(context));
                    continue;
                }
                if (context.testExpression("DBInstanceClass", targetDepth)) {
                    reservedDBInstance.setDBInstanceClass(StringStaxUnmarshaller.getInstance().unmarshall(context));
                    continue;
                }
                if (context.testExpression("StartTime", targetDepth)) {
                    reservedDBInstance.setStartTime(DateStaxUnmarshaller.getInstance().unmarshall(context));
                    continue;
                }
                if (context.testExpression("Duration", targetDepth)) {
                    reservedDBInstance.setDuration(IntegerStaxUnmarshaller.getInstance().unmarshall(context));
                    continue;
                }
                if (context.testExpression("FixedPrice", targetDepth)) {
                    reservedDBInstance.setFixedPrice(DoubleStaxUnmarshaller.getInstance().unmarshall(context));
                    continue;
                }
                if (context.testExpression("UsagePrice", targetDepth)) {
                    reservedDBInstance.setUsagePrice(DoubleStaxUnmarshaller.getInstance().unmarshall(context));
                    continue;
                }
                if (context.testExpression("CurrencyCode", targetDepth)) {
                    reservedDBInstance.setCurrencyCode(StringStaxUnmarshaller.getInstance().unmarshall(context));
                    continue;
                }
                if (context.testExpression("DBInstanceCount", targetDepth)) {
                    reservedDBInstance.setDBInstanceCount(IntegerStaxUnmarshaller.getInstance().unmarshall(context));
                    continue;
                }
                if (context.testExpression("ProductDescription", targetDepth)) {
                    reservedDBInstance.setProductDescription(StringStaxUnmarshaller.getInstance().unmarshall(context));
                    continue;
                }
                if (context.testExpression("OfferingType", targetDepth)) {
                    reservedDBInstance.setOfferingType(StringStaxUnmarshaller.getInstance().unmarshall(context));
                    continue;
                }
                if (context.testExpression("MultiAZ", targetDepth)) {
                    reservedDBInstance.setMultiAZ(BooleanStaxUnmarshaller.getInstance().unmarshall(context));
                    continue;
                }
                if (context.testExpression("State", targetDepth)) {
                    reservedDBInstance.setState(StringStaxUnmarshaller.getInstance().unmarshall(context));
                    continue;
                }
                if (context.testExpression("RecurringCharges/RecurringCharge", targetDepth)) {
                    reservedDBInstance.getRecurringCharges().add(RecurringChargeStaxUnmarshaller.getInstance().unmarshall(context));
                    continue;
                }
            } else if (xmlEvent.isEndElement()) {
                if (context.getCurrentDepth() < originalDepth) {
                    return reservedDBInstance;
                }
            }
        }
    }

    private static ReservedDBInstanceStaxUnmarshaller instance;
    public static ReservedDBInstanceStaxUnmarshaller getInstance() {
        if (instance == null) instance = new ReservedDBInstanceStaxUnmarshaller();
        return instance;
    }
}


text:
<?php

namespace OAuthBundle\Manager;

use Doctrine\ORM\EntityManager;
use OAuthBundle\Exception\ScopeNotFoundException;
use OAuthBundle\Entity\Client;

class ClientManager
{
    private $em;

    /**
     * @var ScopeManagerInterface
     */
    private $sm;

    public function __construct(EntityManager $entityManager, ScopeManagerInterface $scopeManager)
    {
        $this->em = $entityManager;
        $this->sm = $scopeManager;
    }

    /**
     * Creates a new client
     *
     * @param string $identifier
     *
     * @param array $redirect_uris
     *
     * @param array $grant_type
     *
     * @param array $scopes
     *
     * @return Client
     */
    public function createClient($identifier, array $redirect_uris = array(), array $grant_types = array(), array $scopes = array())
    {
        $client = new Client();
        $client->setClientId($identifier);
        $client->setClientSecret($this->generateSecret());
        $client->setRedirectUri($redirect_uris);
        $client->setGrantTypes($grant_types);

        // Verify scopes
        foreach ($scopes as $scope) {
            // Get Scope
            $scopeObject = $this->sm->findScopeByScope($scope);
            if (!$scopeObject) {
                throw new ScopeNotFoundException();
            }
        }

        $client->setScopes($scopes);

        // Store Client
        $this->em->persist($client);
        $this->em->flush();

        return $client;
    }

    /**
     * Creates a secret for a client
     *
     * @return A secret
     */
    protected function generateSecret()
    {
        return base_convert(sha1(uniqid(mt_rand(), true)), 16, 36);
    }
}


text:
class Tag < ActiveRecord::Base
  attr_accessor :obsolete
end


text:
class Shop::ConfigController < ModuleController

  permit 'shop_manage'

  component_info 'shop'

  cms_admin_paths "content",
    "Shop" => { :controller => "/shop/manage" },
    "Configuration" => {:controller => "/shop/config" },
    "Shops" => { :action => "shops" },
    "Carriers" => { :action => "carriers" },
    "Regions" => { :action => "regions" },
    "Shipping Categories" => { :action => "shipping" }

  public

  def index
     cms_page_info [ ["Content",url_for(:controller => '/content') ], ["Shop",url_for(:controller => '/shop/manage') ], "Configuration" ], "content"

   @subpages =
     [
      [ "Site Shops", :shop_config, "website_configuration.gif",
        { :action => "shops" },
        "Add additional shops to your site (1 shop is added by default)"
      ],
      [ "Regions", :shop_config, "system_domains.gif",
         { :action=> 'regions' },
        "Configure the different regions you ship products to"
      ],
      [
         'Delivery Carriers',  :shop_config, "website_configuration.gif",
         { :action => 'carriers' },
         "Configure your delivery carriers for shipping"
      ],
      [
        'Shipping Options',  :shop_config, "system_clients.gif",
         { :action => 'shipping' },
         "Configure the different shipping options for each delivery carrier (Like Ground, 2-Day, etc)"
      ],
      [
        'Payment Processors', :shop_config, "site_editors.gif",
         { :action => 'payment' },
         "Configure payment processing gateways on the site"
      ],
      [ "General Options", :shop_config, "module_setup.gif",
         { :controller => '/shop/admin', :action=> 'options' },
         "Shortcut to Shop module options"
      ]

     ]

  end

   active_table :shops_table,
                Shop::ShopShop,
                [ :check, :name, hdr(:static,"Products" ) ]

   def display_shops_table(display=true)
     active_table_action('shop') do |act,shop_ids|
       if act == 'delete'
         Shop::ShopShop.find(:shop_ids).each do |shop|
           if shop.shop_products.count == 0
             shop.destroy
           else
             flash.now[:notice] = "Cannot delete a shop with products in it"
           end
         end
       end
     end

     @tbl = shops_table_generate params, :order => 'shop_shops.name'

     render :partial => 'shops_table' if display
   end

   def shops
      cms_page_path ["Shop","Configuration"],"Shops"
      display_shops_table(false)
   end

   def shop
    @shop = Shop::ShopShop.find_by_id(params[:path][0]) || Shop::ShopShop.new
      cms_page_path ["Shop","Configuration","Shops"], @shop.new_record? ? "Create Shop" : @shop.name
      if request.post? && params[:shop]
        if !params[:commit]
          redirect_to :action => 'shops'
        elsif @shop.update_attributes(params[:shop])
          redirect_to :action => 'shops'
        end
      end

   end

   active_table :region_table,
                Shop::ShopRegion,
                [ :check,  hdr(:string,:name,:width => 300),  hdr(:number,:tax,:width=> 100),
                  "Subregions","Countries" ]

  def display_region_table(display=true)

     active_table_action('region') do |act,region_ids|
      case act
      when 'delete':
        Shop::ShopRegion.destroy(region_ids)
      end
    end

    @active_table_output = region_table_generate params, {:order => 'name', :include => :countries }
    render :partial => 'region_table' if display
  end

  def regions
    cms_page_path ["Content","Shop","Configuration"],"Regions"
    display_region_table(false)
  end

  def region
    @region = Shop::ShopRegion.find_by_id(params[:path][0]) || Shop::ShopRegion.new

    cms_page_path ["Content","Shop","Configuration","Regions"],
      @region.id ? ["Edit %s",nil,@region.name] :  "Create Region"

    if request.post? && params[:region]
      if params[:commit]
        countries = params[:region].delete(:countries).to_s.strip.split("|")
        country = params[:region].delete(:country)

        @region.attributes = params[:region]
        @region.valid?

        if params[:region][:has_subregions] == '1' && !country.blank?
          countries = [ country  ]
        else
          @region.errors.add(:countries,"must include at least one value") if countries.blank?
        end
        countries.each do |country|
          @region.countries.build(:country => country) unless country.blank?
        end

        if(@region.errors.length == 0 && @region.valid?)
          @region.countries = []
          countries.each do |country|
           @region.countries.build(:country => country) unless country.blank?
          end

          @region.save
          redirect_to :action => 'regions'
        end
      else
        redirect_to :action => 'regions'
      end

     end

  end

   active_table :subregions_table,
                Shop::ShopSubregion,
                [ :check, :name,
                  hdr(:string,:abr,:label => 'Abbreviation'),
                  "Tax"
                ]

  def display_subregions_table(display=true)

     @region = Shop::ShopRegion.find(params[:path][0]) unless @region

     active_table_action('subregion') do |act,subregion_ids|
      case act
      when 'delete':
        Shop::ShopSubregion.destroy_all(subregion_ids)
      end
    end
    if params[:subregion_create] && request.post?
      @created_region = @region.subregions.create(params[:subregion_create])
    end

    @active_table_output = subregions_table_generate params, {:order => 'name' }

    render :partial => 'subregions_table' if display
  end

  def subregions

      @region = Shop::ShopRegion.find(params[:path][0])
       @subregion = @region.subregions.build
     cms_page_info [ ["Content",url_for(:controller => '/content') ], ["Shop",url_for(:controller => '/shop/manage') ],
                     ["Configuration",url_for(:controller => '/shop/config') ],
                     ["Regions",url_for(:action => 'regions') ],
                     ["%s Subregions",nil,@region.name] ], 'content'

    display_subregions_table(false)
  end

 include ActiveTable::Controller
   active_table :carrier_table,
                Shop::ShopCarrier,
                [ ActiveTable::IconHeader.new('',:width => '15'),
                  ActiveTable::StringHeader.new('name', :width => 300),
                  ActiveTable::StaticHeader.new('carrier_processor', :label => 'Type')
                ]

  def display_carriers_table(display=true)

     active_table_action('carrier') do |act,carrier_ids|
      case act
      when 'delete':
        Shop::ShopCarrier.destroy(carrier_ids)
      end
    end

    @active_table_output = carrier_table_generate params, {:order => 'name' }

    render :partial => 'carriers_table' if display
  end

  def carriers
     cms_page_path [ "Content","Shop","Configuration"],"Carriers"
     display_carriers_table(false)
  end

  def carrier

     @handlers = carrier_handlers

     @carrier = Shop::ShopCarrier.find_by_id(params[:path][0]) || Shop::ShopCarrier.new

     cms_page_path [ "Content","Shop","Configuration","Carriers" ],  @carrier.new_record? ? "Create Carrier" : "Edit #{@carrier.name}"

    if request.post? && params[:carrier]
      if params[:commit]
        processor = params[:carrier].delete(:carrier_processor)
        @carrier.carrier_processor = processor if @handlers.detect { |handler| handler[1] == processor }

        if @carrier.update_attributes(params[:carrier])
          redirect_to :action => "carriers"
        end
      else
        redirect_to :action => "carriers"
      end

    end

  end

  protected

  def carrier_handlers
      processors = get_handler_options(:shop,:carrier_processor)
  end

  public

   active_table :shipping_table,
                Shop::ShopShippingCategory,
                [ ActiveTable::IconHeader.new('',:width => '15'),
                  ActiveTable::StringHeader.new('shop_shipping_categories.name', :label => 'Name', :width => 300),
                  ActiveTable::StringHeader.new('shop_regions.name', :label => 'Region'),
                  ActiveTable::StringHeader.new('shop_carriers.name', :label => 'Carrier'),
                  ActiveTable::StaticHeader.new('carrier_processor', :label => 'Type')
                ]

  def display_shipping_table(display=true)

     active_table_action('shipping_category') do |act,cat_ids|
      case act
      when 'delete':
        Shop::ShopShippingCategory.destroy(cat_ids)
      end
    end

    @active_table_output = shipping_table_generate params, {:order => 'shop_shipping_categories.name', :include => [:region, :carrier] }

    render :partial => 'shipping_table' if display
  end

  def shipping
     cms_page_path [ "Content", "Shop","Configuration"],"Shipping Categories"
     display_shipping_table(false)
  end

  def shipping_category

      @shipping_category = Shop::ShopShippingCategory.find_by_id(params[:path][0]) || Shop::ShopShippingCategory.new
      cms_page_path [ "Content", "Shop","Configuration","Shipping Categories"],
        @shipping_category.new_record? ? 'Create Category' : ['Edit %s',nil,@shipping_category.name]

    @shipping_category.attributes = params[:shipping_category] if params[:shipping_category]

    set_shipping_options

    if request.post? && params[:shipping_category]
      if params[:commit]
        @processor.validate_options(@category_options)

        @shipping_category.valid?
        if @category_options && @category_options.errors.length == 0 && @shipping_category.errors.length == 0
          @shipping_category.options= @category_options.to_h
          if @shipping_category.save
            redirect_to :action => "shipping"
            return
          end
        end
      else
       redirect_to :action => "shipping"
      end
    end

    @regions =  [['--Please Select Region--'.t,'']] + Shop::ShopRegion.find_select_options(:all,:order => :name)
    @carriers = [['--Please Select Carrier--'.t,'']] + Shop::ShopCarrier.find_select_options(:all,:order =>:name)

  end

  def update_shipping_options

    @shipping_category = Shop::ShopShippingCategory.find_by_id(params[:path][0]) || Shop::ShopShippingCategory.new
    @shipping_category.shop_carrier_id = params[:carrier_id]

    set_shipping_options

    render :partial => 'shipping_category_options'
  end

  protected

  def set_shipping_options

    if @shipping_category.carrier
      @processor = @shipping_category.carrier.processor

      @category_options = @processor.get_options(params[:category_options] || @shipping_category.options || {})
    end
  end

  public

   active_table :payment_processor_table,
                Shop::ShopPaymentProcessor,
                [ :check, hdr(:boolean,:active),
                  :name,
                  "Currency",
                  "Payment Type",
                  "Processor"
                ]

  def display_payment_processor_table(display=true)

     active_table_action('payment_processor') do |act,processor_ids|
      case act
      when 'delete':
        Shop::ShopPaymentProcessor.destroy(processor_ids)
      when 'activate':
        Shop::ShopPaymentProcessor.find(processor_ids).map { |p| p.update_attributes(:active => true) }
      when 'deactivate':
        Shop::ShopPaymentProcessor.find(processor_ids).map { |p| p.update_attributes(:active => false) }

      end
    end

    @active_table_output = payment_processor_table_generate params, {:order => 'shop_payment_processors.name', :conditions => [ 'payment_type != "Free"']  }

    render :partial => 'payment_processor_table' if display
  end

  def payment

     cms_page_info [ ["Content",url_for(:controller => '/content') ], ["Shop",url_for(:controller => '/shop/manage') ],
                     ["Configuration",url_for(:controller => '/shop/config') ],
                     "Payment Processors" ], 'content'

    display_payment_processor_table(false)
  end

  def processor
      @processor = Shop::ShopPaymentProcessor.find_by_id(params[:path][0]) || Shop::ShopPaymentProcessor.new

     cms_page_info [ ["Content",url_for(:controller => '/content') ], ["Shop",url_for(:controller => '/shop/manage') ],
                     ["Configuration",url_for(:controller => '/shop/config') ],
                     ["Payment Processors",url_for(:action => 'payment') ],
                     @processor.new_record? ? 'Create Processor' : [ "Edit %s",nil,@processor.name ] ], 'content'

      @mod = Shop::AdminController.module_options
      currency = @mod.shop_currency

      @processor.attributes = params[:processor] if params[:processor]
      @processor.currency = currency if !@processor.currency

      @currencies = [  [ currency, currency ] ]

      @payment_processors = get_handler_info(:shop,:payment_processor)

      @payment_types = [ ['--Select Payment Type--',''] ] + @payment_processors.collect do |handler|
        [ handler[:type].t,handler[:type] ]
      end
      @payment_types.uniq!

      @processor.processor_handler = params[:processor][:processor_handler] if params[:processor] && params[:processor][:processor_handler]

      if @processor.payment_type
        @available_processors = [ ['--Select Payment Processor-- ',''] ] + @payment_processors.find_all { |info|
          (!info[:currencies] || info[:currencies].include?(@processor.currency)) && info[:type] == @processor.payment_type
        }.collect { |info| [ info[:name], info[:class_name].underscore ] }
      else
        @processor.processor_handler = ''
      end

      if @processor.processor_handler &&  # if we have a processor
         @payment_processors.detect { |info|  info[:class_name].underscore == @processor.processor_handler } && # and it's a valid processor
         @processor.processor_handler_class.shop_payment_processor_handler_info[:type] == @processor.payment_type ## and it's the right payment type
        @options = @processor.processor_handler_class.get_options(params[:options] || @processor.options)
      else
        @processor.processor_handler = nil
      end

      # Find available
      if request.xhr?
        render :partial => 'processor_form'
        return
      elsif request.post?
        if @processor.valid? && @processor.processor_handler_class.validate_options(@options)
          @processor.options = @options.to_h
          @processor.save
          redirect_to :action => 'payment'
          return
        end
      end

  end

end


text:
//
// This file was generated by the JavaTM Architecture for XML Binding(JAXB) Reference Implementation, v2.2.8-b130911.1802
// See http://java.sun.com/xml/jaxb
// Any modifications to this file will be lost upon recompilation of the source schema.
// Generated on: 2015.08.17 at 11:07:26 AM BST
//

package uk.fstr.darwingateway.bindings;

import javax.xml.bind.annotation.XmlEnum;
import javax.xml.bind.annotation.XmlEnumValue;
import javax.xml.bind.annotation.XmlType;

/**
 *
Java class for AlertType.
 *
 *
The following schema fragment specifies the expected content contained within this class.
 *

 *

 * <simpleType name="AlertType">
 *   <restriction base="{http://www.w3.org/2001/XMLSchema}string">
 *     <enumeration value="Normal"/>
 *     <enumeration value="Forced"/>
 *   </restriction>
 * </simpleType>
 *

 *
 */
@XmlType(name = "AlertType", namespace = "http://www.thalesgroup.com/rtti/PushPort/TrainAlerts/v1")
@XmlEnum
public enum AlertType {

    @XmlEnumValue("Normal")
    NORMAL("Normal"),
    @XmlEnumValue("Forced")
    FORCED("Forced");
    private final String value;

    AlertType(String v) {
        value = v;
    }

    public String value() {
        return value;
    }

    public static AlertType fromValue(String v) {
        for (AlertType c: AlertType.values()) {
            if (c.value.equals(v)) {
                return c;
            }
        }
        throw new IllegalArgumentException(v);
    }

}


text:
using System;
using System.Collections.Generic;
using System.Text;

namespace Sannel.House.Models
{
	public interface IPagedResponse<T>
	{
		/// <summary>
		/// Gets or sets the data.
		/// </summary>
		/// <value>
		/// The data.
		/// </value>
		IEnumerable<T> Data { get; set; }
		/// <summary>
		/// The Total number of items returned by the filter
		/// </summary>
		/// <value>
		/// The total count.
		/// </value>
		long TotalCount { get; set; }
		/// <summary>
		/// Gets or sets the page.
		/// </summary>
		/// <value>
		/// The page.
		/// </value>
		long Page { get; set; }
		/// <summary>
		/// Gets or sets the size of the page.
		/// </summary>
		/// <value>
		/// The size of the page.
		/// </value>
		int PageSize { get; set; }
	}
}


text:
package entities

import (
	"strconv"
	"time"

	libpodEvents "github.com/containers/podman/v3/libpod/events"
	dockerEvents "github.com/docker/docker/api/types/events"
)

// Event combines various event-related data such as time, event type, status
// and more.
type Event struct {
	// TODO: it would be nice to have full control over the types at some
	// point and fork such Docker types.
	dockerEvents.Message
}

// ConvertToLibpodEvent converts an entities event to a libpod one.
func ConvertToLibpodEvent(e Event) *libpodEvents.Event {
	exitCode, err := strconv.Atoi(e.Actor.Attributes["containerExitCode"])
	if err != nil {
		return nil
	}
	status, err := libpodEvents.StringToStatus(e.Action)
	if err != nil {
		return nil
	}
	t, err := libpodEvents.StringToType(e.Type)
	if err != nil {
		return nil
	}
	return &libpodEvents.Event{
		ContainerExitCode: exitCode,
		ID:                e.Actor.ID,
		Image:             e.Actor.Attributes["image"],
		Name:              e.Actor.Attributes["name"],
		Status:            status,
		Time:              time.Unix(e.Time, e.TimeNano),
		Type:              t,
	}
}

// ConvertToEntitiesEvent converts a libpod event to an entities one.
func ConvertToEntitiesEvent(e libpodEvents.Event) *Event {
	return &Event{dockerEvents.Message{
		Type:   e.Type.String(),
		Action: e.Status.String(),
		Actor: dockerEvents.Actor{
			ID: e.ID,
			Attributes: map[string]string{
				"image":             e.Image,
				"name":              e.Name,
				"containerExitCode": strconv.Itoa(e.ContainerExitCode),
			},
		},
		Scope:    "local",
		Time:     e.Time.Unix(),
		TimeNano: e.Time.UnixNano(),
	}}
}


text:
<?php

/**
 * @see SqlAbstract
 */
require_once 'db/sql_abstract.php';

/**
 * SqlInsert
 *
 * Copyright (c) 2011 Curry PHP Framework developers.
 * This software is released under the MIT License.
 *
 * @category   Curry
 * @package    db
 * @copyright  Copyright (c) 2011 Curry PHP Framework developers
 * @link       http://www.curryfw.net
 * @license    MIT License (http://www.opensource.org/licenses/mit-license.php)
 */
class SqlInsert extends SqlAbstract
{
	/**
	 * Add values
	 *
	 * @param mixed $fields Field name or array of combination of field names and values
	 * @param mixed $value Value if $fields is string as fields name
	 * @return SqlAbstract $this Self instance
	 */
	public function values($fields, $value = null)
	{
		$values = array();
		if (is_array($fields)) {
			if ($value != null) {
				throw new Exception('Second argument can not be passed, when first argument is array.');
			}
			foreach ($fields as $col => $val) {
				$values[$col] = $val;
			}
		} else {
			$values[$fields] = $value;
		}

		foreach ($values as $col => $val) {
			$this->_parts['fields'][] = $col;
			if ($val === null || (self::$_convertEmptyToNull == true && $val === '')) {
				$this->_parts['values'][] = "NULL";
			} else if ($val instanceof SqlSelect) {
				$subQuery = $val;
				$this->_parts['values'][] = '(' . $subQuery->getSql() . ')';
				$subParams = $subQuery->getParams();
				foreach ($subParams as $subCol => $subVal) {
					$this->_params[$subCol] = $subVal;
				}
			} else {
				$paramKey = $this->_createParamKey();
				$this->_parts['values'][] = ':' . $paramKey;
				$this->_params[$paramKey] = $val;
			}
		}

		return $this;
	}

	/**
	 * Create and return SQL sentence
	 *
	 * @return string SQL sentence
	 */
	public function getSql()
	{
		$fieldsStr = implode(',', $this->_parts['fields']);
		$valsStr = implode(',', $this->_parts['values']);
		$tableName = $this->_getTableFullName();
		$sql = sprintf("INSERT INTO %s (%s) VALUES (%s)", $tableName, $fieldsStr, $valsStr);

		return $sql;
	}

	/**
	 * Execute insert sentence.
	 * It fails, when conditions are not specified.
	 *
	 * @return boolean
	 */
	public function execute()
	{
		$res = parent::execute();
		if ($res === false) {
			return false;
		}
		$res = $this->_adapter->lastInsertId();
		return $res;
	}

}


text:
"""
Functions for determining information about a referenced work.
"""

from refkit.lookup   import arxiv
from refkit.lookup   import crossref
from refkit.metadata import Metadata

from refkit.util.doi import extract

def getMetadata(input, autoSaveMinimum = crossref.defAutoSaveMinimum, autoSaveMaximum = crossref.defAutoSaveMaximum):
    """
    Gather metadata for a reference. In some cases it may be possible that multiple Metadata objects are returned.
    For example, if an arXiv reference is found, and it has a DOI associated with it, the metadata for the article
    with that DOI will also be returned. In all cases, the first item returned is the primary reference.

    :param input: String with the reference to extract metadata for
    :param autoSaveMinimum: Minimum value for overlap score to be valid without user intervention (0 - 1)
    :param autoSaveMaximum: Maximum ratio of the second best to best overlaps for a result to be valid without
                            user intervention (0 - 1)
    :returns: List of Metadata objects with the metadata that was gathered
    """
    return _getMetadataByLookup(input, autoSaveMinimum, autoSaveMaximum)

def _getMetadataByLookup(input, autoSaveMinimum, autoSaveMaximum):
    """
    Gather metadata for a reference by searching for information on lookup services.

    :param input: String with the reference to extract metadata for
    :param autoSaveMinimum: Minimum value for overlap score to be valid without user intervention (0 - 1)
    :param autoSaveMaximum: Maximum ratio of the second best to best overlaps for a result to be valid without
                            user intervention (0 - 1)
    :returns: List of Metadata objects with the metadata that was gathered
    """
    res  = _getMetadataFromArxiv(input)
    res += _getMetadataFromCrossref(input, res, autoSaveMinimum, autoSaveMaximum)
    return res

def _getMetadataFromArxiv(input):
    """
    Gather metadata for a reference from arXiv.org.

    :param input: String with the reference to extract metadata for
    :returns: Metadata object with the information that was gathered
    """
    try:
        return [ arxiv.search(input) ]
    except Exception:
        return []

def _getMetadataFromCrossref(input, existingMetadata, autoSaveMinimum, autoSaveMaximum):
    """
    Gather metadata for a reference from CrossRef.org. This function first tries to use metadata already gathered to
    search CrossRef.org, then uses the input string if metadata did not produce a result.

    :param input: String with the reference to extract metadata for
    :param existingMetadata: List of metadata objects already determined for input
    :param autoSaveMinimum: Minimum value for overlap score to be valid without user intervention (0 - 1)
    :param autoSaveMaximum: Maximum ratio of the second best to best overlaps for a result to be valid without
                            user intervention (0 - 1)
    :returns: Metadata object with the information that was gathered
    """
    for i in existingMetadata:
        try:
            return [ crossref.search(i.toUnformattedString(), autoSaveMinimum, autoSaveMaximum) ]
        except Exception, e:
            pass
    if len(existingMetadata) == 0:
        try:
            return [ crossref.search(input, autoSaveMinimum, autoSaveMaximum) ]
        except:
            pass
        return _promptForManualEntry(input)
    return []

def _promptForManualEntry(input):
    """
    Ask the user if they want to manual set the metadata for the object.

    :param input: String with the reference data being searched for.
    :returns: Metadata object with the information that was gathered or emtpy array.
    """
    print ''
    print 'LOOKUP STRING: ' + input
    return [] if _getResponse('Do you want to manually set the information [y/n]: ') == 'n' else _getDataFromUser()

def _getDataFromUser():
    """
    Ask the user whether they have a better lookup string.

    :returns: Metadata object with the information that was gathered or emtpy array.
    """
    print ''
    input = raw_input('Better lookup string: ')
    res = []
    if len(input) > 0:
        res = _getMetadataByLookup(input, crossref.defAutoSaveMinimum, crossref.defAutoSaveMaximum)
    if len(res) == 0:
        res = [ Metadata().getDataFromUser() ]
    return res

def _getResponse(message):
    """
    Get a y/n response from the user.

    :param message: Message to print to the user.
    :returns: Response from the user.
    """
    res = ''
    while res != 'y' and res != 'n':
        res = raw_input(message)
    return res