text:
// Copyright 2010-2022 Google LLC
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#include "ortools/sat/boolean_problem.h"

#include <algorithm>
#include <cmath>
#include <cstdint>
#include <cstdlib>
#include <limits>
#include <memory>
#include <numeric>
#include <string>
#include <utility>
#include <vector>

#include "absl/container/flat_hash_map.h"
#include "absl/flags/flag.h"
#include "absl/status/status.h"
#include "absl/strings/str_format.h"
#include "absl/strings/string_view.h"
#include "ortools/base/logging.h"
#include "ortools/graph/graph.h"
#if !defined(__PORTABLE_PLATFORM__)
#include "ortools/graph/io.h"
#endif  // __PORTABLE_PLATFORM__
#include "ortools/algorithms/find_graph_symmetries.h"
#include "ortools/algorithms/sparse_permutation.h"
#include "ortools/base/strong_vector.h"
#include "ortools/graph/util.h"
#include "ortools/port/proto_utils.h"
#include "ortools/sat/boolean_problem.pb.h"
#include "ortools/sat/cp_model.pb.h"
#include "ortools/sat/pb_constraint.h"
#include "ortools/sat/sat_base.h"
#include "ortools/sat/sat_parameters.pb.h"
#include "ortools/sat/sat_solver.h"
#include "ortools/sat/simplification.h"
#include "ortools/util/strong_integers.h"

ABSL_FLAG(std::string, debug_dump_symmetry_graph_to_file, "",
          "If this flag is non-empty, an undirected graph whose"
          " automorphism group is in one-to-one correspondence with the"
          " symmetries of the SAT problem will be dumped to a file every"
          " time FindLinearBooleanProblemSymmetries() is called.");

namespace operations_research {
namespace sat {

using util::RemapGraph;

void ExtractAssignment(const LinearBooleanProblem& problem,
                       const SatSolver& solver, std::vector<bool>* assignment) {
  assignment->clear();
  for (int i = 0; i < problem.num_variables(); ++i) {
    assignment->push_back(
        solver.Assignment().LiteralIsTrue(Literal(BooleanVariable(i), true)));
  }
}

namespace {

// Used by BooleanProblemIsValid() to test that there is no duplicate literals,
// that they are all within range and that there is no zero coefficient.
//
// A non-empty string indicates an error.
template <typename LinearTerms>
std::string ValidateLinearTerms(const LinearTerms& terms,
                                std::vector<bool>* variable_seen) {
  // variable_seen already has all items false and is reset before return.
  std::string err_str;
  int num_errs = 0;
  const int max_num_errs = 100;
  for (int i = 0; i < terms.literals_size(); ++i) {
    if (terms.literals(i) == 0) {
      if (++num_errs <= max_num_errs) {
        err_str += absl::StrFormat("Zero literal at position %d\n", i);
      }
    }
    if (terms.coefficients(i) == 0) {
      if (++num_errs <= max_num_errs) {
        err_str += absl::StrFormat("Literal %d has a zero coefficient\n",
                                   terms.literals(i));
      }
    }
    const int var = Literal(terms.literals(i)).Variable().value();
    if (var >= variable_seen->size()) {
      if (++num_errs <= max_num_errs) {
        err_str += absl::StrFormat("Out of bound variable %d\n", var);
      }
    }
    if ((*variable_seen)[var]) {
      if (++num_errs <= max_num_errs) {
        err_str += absl::StrFormat("Duplicated variable %d\n", var);
      }
    }
    (*variable_seen)[var] = true;
  }

  for (int i = 0; i < terms.literals_size(); ++i) {
    const int var = Literal(terms.literals(i)).Variable().value();
    (*variable_seen)[var] = false;
  }
  if (num_errs) {
    if (num_errs <= max_num_errs) {
      err_str = absl::StrFormat("%d validation errors:\n", num_errs) + err_str;
    } else {
      err_str =
          absl::StrFormat("%d validation errors; here are the first %d:\n",
                          num_errs, max_num_errs) +
          err_str;
    }
  }
  return err_str;
}

// Converts a linear expression from the protocol buffer format to a vector
// of LiteralWithCoeff.
template <typename ProtoFormat>
std::vector<LiteralWithCoeff> ConvertLinearExpression(
    const ProtoFormat& input) {
  std::vector<LiteralWithCoeff> cst;
  cst.reserve(input.literals_size());
  for (int i = 0; i < input.literals_size(); ++i) {
    const Literal literal(input.literals(i));
    cst.push_back(LiteralWithCoeff(literal, input.coefficients(i)));
  }
  return cst;
}

}  // namespace

absl::Status ValidateBooleanProblem(const LinearBooleanProblem& problem) {
  std::vector<bool> variable_seen(problem.num_variables(), false);
  for (int i = 0; i < problem.constraints_size(); ++i) {
    const LinearBooleanConstraint& constraint = problem.constraints(i);
    const std::string error = ValidateLinearTerms(constraint, &variable_seen);
    if (!error.empty()) {
      return absl::Status(
          absl::StatusCode::kInvalidArgument,
          absl::StrFormat("Invalid constraint %i: ", i) + error);
    }
  }
  const std::string error =
      ValidateLinearTerms(problem.objective(), &variable_seen);
  if (!error.empty()) {
    return absl::Status(absl::StatusCode::kInvalidArgument,
                        absl::StrFormat("Invalid objective: ") + error);
  }
  return ::absl::OkStatus();
}

CpModelProto BooleanProblemToCpModelproto(const LinearBooleanProblem& problem) {
  CpModelProto result;
  for (int i = 0; i < problem.num_variables(); ++i) {
    IntegerVariableProto* var = result.add_variables();
    if (problem.var_names_size() > i) {
      var->set_name(problem.var_names(i));
    }
    var->add_domain(0);
    var->add_domain(1);
  }
  for (const LinearBooleanConstraint& constraint : problem.constraints()) {
    ConstraintProto* ct = result.add_constraints();
    ct->set_name(constraint.name());
    LinearConstraintProto* linear = ct->mutable_linear();
    int64_t offset = 0;
    for (int i = 0; i < constraint.literals_size(); ++i) {
      // Note that the new format is slightly different.
      const int lit = constraint.literals(i);
      const int64_t coeff = constraint.coefficients(i);
      if (lit > 0) {
        linear->add_vars(lit - 1);
        linear->add_coeffs(coeff);
      } else {
        // The term was coeff * (1 - var).
        linear->add_vars(-lit - 1);
        linear->add_coeffs(-coeff);
        offset -= coeff;
      }
    }
    linear->add_domain(constraint.has_lower_bound()
                           ? constraint.lower_bound() + offset
                           : std::numeric_limits<int32_t>::min() + offset);
    linear->add_domain(constraint.has_upper_bound()
                           ? constraint.upper_bound() + offset
                           : std::numeric_limits<int32_t>::max() + offset);
  }
  if (problem.has_objective()) {
    CpObjectiveProto* objective = result.mutable_objective();
    int64_t offset = 0;
    for (int i = 0; i < problem.objective().literals_size(); ++i) {
      const int lit = problem.objective().literals(i);
      const int64_t coeff = problem.objective().coefficients(i);
      if (lit > 0) {
        objective->add_vars(lit - 1);
        objective->add_coeffs(coeff);
      } else {
        objective->add_vars(-lit - 1);
        objective->add_coeffs(-coeff);
        offset -= coeff;
      }
    }
    objective->set_offset(offset + problem.objective().offset());
    objective->set_scaling_factor(problem.objective().scaling_factor());
  }
  return result;
}

void ChangeOptimizationDirection(LinearBooleanProblem* problem) {
  LinearObjective* objective = problem->mutable_objective();
  objective->set_scaling_factor(-objective->scaling_factor());
  objective->set_offset(-objective->offset());
  // We need 'auto' here to keep the open-source compilation happy
  // (it uses the public protobuf release).
  for (auto& coefficients_ref : *objective->mutable_coefficients()) {
    coefficients_ref = -coefficients_ref;
  }
}

bool LoadBooleanProblem(const LinearBooleanProblem& problem,
                        SatSolver* solver) {
  // TODO(user): Currently, the sat solver can load without any issue
  // constraints with duplicate variables, so we just output a warning if the
  // problem is not "valid". Make this a strong check once we have some
  // preprocessing step to remove duplicates variable in the constraints.
  const absl::Status status = ValidateBooleanProblem(problem);
  if (!status.ok()) {
    LOG(WARNING) << "The given problem is invalid!";
  }

  if (solver->parameters().log_search_progress()) {
    LOG(INFO) << "Loading problem '" << problem.name() << "', "
              << problem.num_variables() << " variables, "
              << problem.constraints_size() << " constraints.";
  }
  solver->SetNumVariables(problem.num_variables());
  std::vector<LiteralWithCoeff> cst;
  int64_t num_terms = 0;
  int num_constraints = 0;
  for (const LinearBooleanConstraint& constraint : problem.constraints()) {
    num_terms += constraint.literals_size();
    cst = ConvertLinearExpression(constraint);
    if (!solver->AddLinearConstraint(
            constraint.has_lower_bound(), Coefficient(constraint.lower_bound()),
            constraint.has_upper_bound(), Coefficient(constraint.upper_bound()),
            &cst)) {
      LOG(INFO) << "Problem detected to be UNSAT when "
                << "adding the constraint #" << num_constraints
                << " with name '" << constraint.name() << "'";
      return false;
    }
    ++num_constraints;
  }
  if (solver->parameters().log_search_progress()) {
    LOG(INFO) << "The problem contains " << num_terms << " terms.";
  }
  return true;
}

bool LoadAndConsumeBooleanProblem(LinearBooleanProblem* problem,
                                  SatSolver* solver) {
  const absl::Status status = ValidateBooleanProblem(*problem);
  if (!status.ok()) {
    LOG(WARNING) << "The given problem is invalid! " << status.message();
  }
  if (solver->parameters().log_search_progress()) {
#if !defined(__PORTABLE_PLATFORM__)
    LOG(INFO) << "LinearBooleanProblem memory: " << problem->SpaceUsedLong();
#endif
    LOG(INFO) << "Loading problem '" << problem->name() << "', "
              << problem->num_variables() << " variables, "
              << problem->constraints_size() << " constraints.";
  }
  solver->SetNumVariables(problem->num_variables());
  std::vector<LiteralWithCoeff> cst;
  int64_t num_terms = 0;
  int num_constraints = 0;

  // We will process the constraints backward so we can free the memory used by
  // each constraint just after processing it. Because of that, we initially
  // reverse all the constraints to add them in the same order.
  std::reverse(problem->mutable_constraints()->begin(),
               problem->mutable_constraints()->end());
  for (int i = problem->constraints_size() - 1; i >= 0; --i) {
    const LinearBooleanConstraint& constraint = problem->constraints(i);
    num_terms += constraint.literals_size();
    cst = ConvertLinearExpression(constraint);
    if (!solver->AddLinearConstraint(
            constraint.has_lower_bound(), Coefficient(constraint.lower_bound()),
            constraint.has_upper_bound(), Coefficient(constraint.upper_bound()),
            &cst)) {
      LOG(INFO) << "Problem detected to be UNSAT when "
                << "adding the constraint #" << num_constraints
                << " with name '" << constraint.name() << "'";
      return false;
    }
    delete problem->mutable_constraints()->ReleaseLast();
    ++num_constraints;
  }
  LinearBooleanProblem empty_problem;
  problem->mutable_constraints()->Swap(empty_problem.mutable_constraints());
  if (solver->parameters().log_search_progress()) {
    LOG(INFO) << "The problem contains " << num_terms << " terms.";
  }
  return true;
}

void UseObjectiveForSatAssignmentPreference(const LinearBooleanProblem& problem,
                                            SatSolver* solver) {
  const LinearObjective& objective = problem.objective();
  CHECK_EQ(objective.literals_size(), objective.coefficients_size());
  int64_t max_abs_weight = 0;
  for (const int64_t coefficient : objective.coefficients()) {
    max_abs_weight = std::max(max_abs_weight, std::abs(coefficient));
  }
  const double max_abs_weight_double = max_abs_weight;
  for (int i = 0; i < objective.literals_size(); ++i) {
    const Literal literal(objective.literals(i));
    const int64_t coefficient = objective.coefficients(i);
    const double abs_weight = std::abs(coefficient) / max_abs_weight_double;
    // Because this is a minimization problem, we prefer to assign a Boolean
    // variable to its "low" objective value. So if a literal has a positive
    // weight when true, we want to set it to false.
    solver->SetAssignmentPreference(
        coefficient > 0 ? literal.Negated() : literal, abs_weight);
  }
}

bool AddObjectiveUpperBound(const LinearBooleanProblem& problem,
                            Coefficient upper_bound, SatSolver* solver) {
  std::vector<LiteralWithCoeff> cst =
      ConvertLinearExpression(problem.objective());
  return solver->AddLinearConstraint(false, Coefficient(0), true, upper_bound,
                                     &cst);
}

bool AddObjectiveConstraint(const LinearBooleanProblem& problem,
                            bool use_lower_bound, Coefficient lower_bound,
                            bool use_upper_bound, Coefficient upper_bound,
                            SatSolver* solver) {
  std::vector<LiteralWithCoeff> cst =
      ConvertLinearExpression(problem.objective());
  return solver->AddLinearConstraint(use_lower_bound, lower_bound,
                                     use_upper_bound, upper_bound, &cst);
}

Coefficient ComputeObjectiveValue(const LinearBooleanProblem& problem,
                                  const std::vector<bool>& assignment) {
  CHECK_EQ(assignment.size(), problem.num_variables());
  Coefficient sum(0);
  const LinearObjective& objective = problem.objective();
  for (int i = 0; i < objective.literals_size(); ++i) {
    const Literal literal(objective.literals(i));
    if (assignment[literal.Variable().value()] == literal.IsPositive()) {
      sum += objective.coefficients(i);
    }
  }
  return sum;
}

bool IsAssignmentValid(const LinearBooleanProblem& problem,
                       const std::vector<bool>& assignment) {
  CHECK_EQ(assignment.size(), problem.num_variables());

  // Check that all constraints are satisfied.
  for (const LinearBooleanConstraint& constraint : problem.constraints()) {
    Coefficient sum(0);
    for (int i = 0; i < constraint.literals_size(); ++i) {
      const Literal literal(constraint.literals(i));
      if (assignment[literal.Variable().value()] == literal.IsPositive()) {
        sum += constraint.coefficients(i);
      }
    }
    if (constraint.has_lower_bound() && sum < constraint.lower_bound()) {
      LOG(WARNING) << "Unsatisfied constraint! sum: " << sum << "\n"
                   << ProtobufDebugString(constraint);
      return false;
    }
    if (constraint.has_upper_bound() && sum > constraint.upper_bound()) {
      LOG(WARNING) << "Unsatisfied constraint! sum: " << sum << "\n"
                   << ProtobufDebugString(constraint);
      return false;
    }
  }
  return true;
}

// Note(user): This function makes a few assumptions about the format of the
// given LinearBooleanProblem. All constraint coefficients must be 1 (and of the
// form >= 1) and all objective weights must be strictly positive.
std::string LinearBooleanProblemToCnfString(
    const LinearBooleanProblem& problem) {
  std::string output;
  const bool is_wcnf = (problem.objective().coefficients_size() > 0);
  const LinearObjective& objective = problem.objective();

  // Hack: We know that all the variables with index greater than this have been
  // created "artificially" in order to encode a max-sat problem into our
  // format. Each extra variable appear only once, and was used as a slack to
  // reify a soft clause.
  const int first_slack_variable = problem.original_num_variables();

  // This will contains the objective.
  absl::flat_hash_map<int, int64_t> literal_to_weight;
  std::vector<std::pair<int, int64_t>> non_slack_objective;

  // This will be the weight of the "hard" clauses in the wcnf format. It must
  // be greater than the sum of the weight of all the soft clauses, so we will
  // just set it to this sum + 1.
  int64_t hard_weight = 1;
  if (is_wcnf) {
    int i = 0;
    for (int64_t weight : objective.coefficients()) {
      CHECK_NE(weight, 0);
      int signed_literal = objective.literals(i);

      // There is no direct support for an objective offset in the wcnf format.
      // So this is not a perfect translation of the objective. It is however
      // possible to achieve the same effect by adding a new variable x, and two
      // soft clauses: x with weight offset, and -x with weight offset.
      //
      // TODO(user): implement this trick.
      if (weight < 0) {
        signed_literal = -signed_literal;
        weight = -weight;
      }
      literal_to_weight[objective.literals(i)] = weight;
      if (Literal(signed_literal).Variable() < first_slack_variable) {
        non_slack_objective.push_back(std::make_pair(signed_literal, weight));
      }
      hard_weight += weight;
      ++i;
    }
    output += absl::StrFormat("p wcnf %d %d %d\n", first_slack_variable,
                              static_cast<int>(problem.constraints_size() +
                                               non_slack_objective.size()),
                              hard_weight);
  } else {
    output += absl::StrFormat("p cnf %d %d\n", problem.num_variables(),
                              problem.constraints_size());
  }

  std::string constraint_output;
  for (const LinearBooleanConstraint& constraint : problem.constraints()) {
    if (constraint.literals_size() == 0) return "";  // Assumption.
    constraint_output.clear();
    int64_t weight = hard_weight;
    for (int i = 0; i < constraint.literals_size(); ++i) {
      if (constraint.coefficients(i) != 1) return "";  // Assumption.
      if (is_wcnf && abs(constraint.literals(i)) - 1 >= first_slack_variable) {
        weight = literal_to_weight[constraint.literals(i)];
      } else {
        if (i > 0) constraint_output += " ";
        constraint_output += Literal(constraint.literals(i)).DebugString();
      }
    }
    if (is_wcnf) {
      output += absl::StrFormat("%d ", weight);
    }
    output += constraint_output + " 0\n";
  }

  // Output the rest of the objective as singleton constraints.
  if (is_wcnf) {
    for (std::pair<int, int64_t> p : non_slack_objective) {
      // Since it is falsifying this clause that cost "weigtht", we need to take
      // its negation.
      const Literal literal(-p.first);
      output += absl::StrFormat("%d %s 0\n", p.second, literal.DebugString());
    }
  }

  return output;
}

void StoreAssignment(const VariablesAssignment& assignment,
                     BooleanAssignment* output) {
  output->clear_literals();
  for (BooleanVariable var(0); var < assignment.NumberOfVariables(); ++var) {
    if (assignment.VariableIsAssigned(var)) {
      output->add_literals(
          assignment.GetTrueLiteralForAssignedVariable(var).SignedValue());
    }
  }
}

void ExtractSubproblem(const LinearBooleanProblem& problem,
                       const std::vector<int>& constraint_indices,
                       LinearBooleanProblem* subproblem) {
  *subproblem = problem;
  subproblem->set_name("Subproblem of " + problem.name());
  subproblem->clear_constraints();
  for (int index : constraint_indices) {
    CHECK_LT(index, problem.constraints_size());
    subproblem->add_constraints()->MergeFrom(problem.constraints(index));
  }
}

namespace {
// A simple class to generate equivalence class number for
// GenerateGraphForSymmetryDetection().
class IdGenerator {
 public:
  IdGenerator() {}

  // If the pair (type, coefficient) was never seen before, then generate
  // a new id, otherwise return the previously generated id.
  int GetId(int type, Coefficient coefficient) {
    const std::pair<int, int64_t> key(type, coefficient.value());
    return id_map_.emplace(key, id_map_.size()).first->second;
  }

 private:
  absl::flat_hash_map<std::pair<int, int64_t>, int> id_map_;
};
}  // namespace.

// Returns a graph whose automorphisms can be mapped back to the symmetries of
// the given LinearBooleanProblem.
//
// Any permutation of the graph that respects the initial_equivalence_classes
// output can be mapped to a symmetry of the given problem simply by taking its
// restriction on the first 2 * num_variables nodes and interpreting its index
// as a literal index. In a sense, a node with a low enough index #i is in
// one-to-one correspondence with a literals #i (using the index representation
// of literal).
//
// The format of the initial_equivalence_classes is the same as the one
// described in GraphSymmetryFinder::FindSymmetries(). The classes must be dense
// in [0, num_classes) and any symmetry will only map nodes with the same class
// between each other.
template <typename Graph>
Graph* GenerateGraphForSymmetryDetection(
    const LinearBooleanProblem& problem,
    std::vector<int>* initial_equivalence_classes) {
  // First, we convert the problem to its canonical representation.
  const int num_variables = problem.num_variables();
  CanonicalBooleanLinearProblem canonical_problem;
  std::vector<LiteralWithCoeff> cst;
  for (const LinearBooleanConstraint& constraint : problem.constraints()) {
    cst = ConvertLinearExpression(constraint);
    CHECK(canonical_problem.AddLinearConstraint(
        constraint.has_lower_bound(), Coefficient(constraint.lower_bound()),
        constraint.has_upper_bound(), Coefficient(constraint.upper_bound()),
        &cst));
  }

  // TODO(user): reserve the memory for the graph? not sure it is worthwhile
  // since it would require some linear scan of the problem though.
  Graph* graph = new Graph();
  initial_equivalence_classes->clear();

  // We will construct a graph with 3 different types of node that must be
  // in different equivalent classes.
  enum NodeType { LITERAL_NODE, CONSTRAINT_NODE, CONSTRAINT_COEFFICIENT_NODE };
  IdGenerator id_generator;

  // First, we need one node per literal with an edge between each literal
  // and its negation.
  for (int i = 0; i < num_variables; ++i) {
    // We have two nodes for each variable.
    // Note that the indices are in [0, 2 * num_variables) and in one to one
    // correspondence with the index representation of a literal.
    const Literal literal = Literal(BooleanVariable(i), true);
    graph->AddArc(literal.Index().value(), literal.NegatedIndex().value());
    graph->AddArc(literal.NegatedIndex().value(), literal.Index().value());
  }

  // We use 0 for their initial equivalence class, but that may be modified
  // with the objective coefficient (see below).
  initial_equivalence_classes->assign(
      2 * num_variables,
      id_generator.GetId(NodeType::LITERAL_NODE, Coefficient(0)));

  // Literals with different objective coeffs shouldn't be in the same class.
  //
  // We need to canonicalize the objective to regroup literals corresponding
  // to the same variables. Note that we don't care about the offset or
  // optimization direction here, we just care about literals with the same
  // canonical coefficient.
  Coefficient shift;
  Coefficient max_value;
  std::vector<LiteralWithCoeff> expr =
      ConvertLinearExpression(problem.objective());
  ComputeBooleanLinearExpressionCanonicalForm(&expr, &shift, &max_value);
  for (LiteralWithCoeff term : expr) {
    (*initial_equivalence_classes)[term.literal.Index().value()] =
        id_generator.GetId(NodeType::LITERAL_NODE, term.coefficient);
  }

  // Then, for each constraint, we will have one or more nodes.
  for (int i = 0; i < canonical_problem.NumConstraints(); ++i) {
    // First we have a node for the constraint with an equivalence class
    // depending on the rhs.
    //
    // Note: Since we add nodes one by one, initial_equivalence_classes->size()
    // gives the number of nodes at any point, which we use as next node index.
    const int constraint_node_index = initial_equivalence_classes->size();
    initial_equivalence_classes->push_back(id_generator.GetId(
        NodeType::CONSTRAINT_NODE, canonical_problem.Rhs(i)));

    // This node will also be connected to all literals of the constraint
    // with a coefficient of 1. Literals with new coefficients will be grouped
    // under a new node connected to the constraint_node_index.
    //
    // Note that this works because a canonical constraint is sorted by
    // increasing coefficient value (all positive).
    int current_node_index = constraint_node_index;
    Coefficient previous_coefficient(1);
    for (LiteralWithCoeff term : canonical_problem.Constraint(i)) {
      if (term.coefficient != previous_coefficient) {
        current_node_index = initial_equivalence_classes->size();
        initial_equivalence_classes->push_back(id_generator.GetId(
            NodeType::CONSTRAINT_COEFFICIENT_NODE, term.coefficient));
        previous_coefficient = term.coefficient;

        // Connect this node to the constraint node. Note that we don't
        // technically need the arcs in both directions, but that may help a bit
        // the algorithm to find symmetries.
        graph->AddArc(constraint_node_index, current_node_index);
        graph->AddArc(current_node_index, constraint_node_index);
      }

      // Connect this node to the associated term.literal node. Note that we
      // don't technically need the arcs in both directions, but that may help a
      // bit the algorithm to find symmetries.
      graph->AddArc(current_node_index, term.literal.Index().value());
      graph->AddArc(term.literal.Index().value(), current_node_index);
    }
  }
  graph->Build();
  DCHECK_EQ(graph->num_nodes(), initial_equivalence_classes->size());
  return graph;
}

void MakeAllLiteralsPositive(LinearBooleanProblem* problem) {
  // Objective.
  LinearObjective* mutable_objective = problem->mutable_objective();
  int64_t objective_offset = 0;
  for (int i = 0; i < mutable_objective->literals_size(); ++i) {
    const int signed_literal = mutable_objective->literals(i);
    if (signed_literal < 0) {
      const int64_t coefficient = mutable_objective->coefficients(i);
      mutable_objective->set_literals(i, -signed_literal);
      mutable_objective->set_coefficients(i, -coefficient);
      objective_offset += coefficient;
    }
  }
  mutable_objective->set_offset(mutable_objective->offset() + objective_offset);

  // Constraints.
  for (LinearBooleanConstraint& constraint :
       *(problem->mutable_constraints())) {
    int64_t sum = 0;
    for (int i = 0; i < constraint.literals_size(); ++i) {
      if (constraint.literals(i) < 0) {
        sum += constraint.coefficients(i);
        constraint.set_literals(i, -constraint.literals(i));
        constraint.set_coefficients(i, -constraint.coefficients(i));
      }
    }
    if (constraint.has_lower_bound()) {
      constraint.set_lower_bound(constraint.lower_bound() - sum);
    }
    if (constraint.has_upper_bound()) {
      constraint.set_upper_bound(constraint.upper_bound() - sum);
    }
  }
}

void FindLinearBooleanProblemSymmetries(
    const LinearBooleanProblem& problem,
    std::vector<std::unique_ptr<SparsePermutation>>* generators) {
  typedef GraphSymmetryFinder::Graph Graph;
  std::vector<int> equivalence_classes;
  std::unique_ptr<Graph> graph(
      GenerateGraphForSymmetryDetection<Graph>(problem, &equivalence_classes));
  LOG(INFO) << "Graph has " << graph->num_nodes() << " nodes and "
            << graph->num_arcs() / 2 << " edges.";
#if !defined(__PORTABLE_PLATFORM__)
  if (!absl::GetFlag(FLAGS_debug_dump_symmetry_graph_to_file).empty()) {
    // Remap the graph nodes to sort them by equivalence classes.
    std::vector<int> new_node_index(graph->num_nodes(), -1);
    const int num_classes = 1 + *std::max_element(equivalence_classes.begin(),
                                                  equivalence_classes.end());
    std::vector<int> class_size(num_classes, 0);
    for (const int c : equivalence_classes) ++class_size[c];
    std::vector<int> next_index_by_class(num_classes, 0);
    std::partial_sum(class_size.begin(), class_size.end() - 1,
                     next_index_by_class.begin() + 1);
    for (int node = 0; node < graph->num_nodes(); ++node) {
      new_node_index[node] = next_index_by_class[equivalence_classes[node]]++;
    }
    std::unique_ptr<Graph> remapped_graph = RemapGraph(*graph, new_node_index);
    const absl::Status status = util::WriteGraphToFile(
        *remapped_graph, absl::GetFlag(FLAGS_debug_dump_symmetry_graph_to_file),
        /*directed=*/false, class_size);
    if (!status.ok()) {
      LOG(DFATAL) << "Error when writing the symmetry graph to file: "
                  << status;
    }
  }
#endif  // __PORTABLE_PLATFORM__
  GraphSymmetryFinder symmetry_finder(*graph,
                                      /*is_undirected=*/true);
  std::vector<int> factorized_automorphism_group_size;
  // TODO(user): inject the appropriate time limit here.
  CHECK(symmetry_finder
            .FindSymmetries(&equivalence_classes, generators,
                            &factorized_automorphism_group_size)
            .ok());

  // Remove from the permutations the part not concerning the literals.
  // Note that some permutation may becomes empty, which means that we had
  // duplicates constraints. TODO(user): Remove them beforehand?
  double average_support_size = 0.0;
  int num_generators = 0;
  for (int i = 0; i < generators->size(); ++i) {
    SparsePermutation* permutation = (*generators)[i].get();
    std::vector<int> to_delete;
    for (int j = 0; j < permutation->NumCycles(); ++j) {
      if (*(permutation->Cycle(j).begin()) >= 2 * problem.num_variables()) {
        to_delete.push_back(j);
        if (DEBUG_MODE) {
          // Verify that the cycle's entire support does not touch any variable.
          for (const int node : permutation->Cycle(j)) {
            DCHECK_GE(node, 2 * problem.num_variables());
          }
        }
      }
    }
    permutation->RemoveCycles(to_delete);
    if (!permutation->Support().empty()) {
      average_support_size += permutation->Support().size();
      swap((*generators)[num_generators], (*generators)[i]);
      ++num_generators;
    }
  }
  generators->resize(num_generators);
  average_support_size /= num_generators;
  LOG(INFO) << "# of generators: " << num_generators;
  LOG(INFO) << "Average support size: " << average_support_size;
}

void ApplyLiteralMappingToBooleanProblem(
    const absl::StrongVector<LiteralIndex, LiteralIndex>& mapping,
    LinearBooleanProblem* problem) {
  Coefficient bound_shift;
  Coefficient max_value;
  std::vector<LiteralWithCoeff> cst;

  // First the objective.
  cst = ConvertLinearExpression(problem->objective());
  ApplyLiteralMapping(mapping, &cst, &bound_shift, &max_value);
  LinearObjective* mutable_objective = problem->mutable_objective();
  mutable_objective->clear_literals();
  mutable_objective->clear_coefficients();
  mutable_objective->set_offset(mutable_objective->offset() -
                                bound_shift.value());
  for (const LiteralWithCoeff& entry : cst) {
    mutable_objective->add_literals(entry.literal.SignedValue());
    mutable_objective->add_coefficients(entry.coefficient.value());
  }

  // Now the clauses.
  for (LinearBooleanConstraint& constraint : *problem->mutable_constraints()) {
    cst = ConvertLinearExpression(constraint);
    constraint.clear_literals();
    constraint.clear_coefficients();
    ApplyLiteralMapping(mapping, &cst, &bound_shift, &max_value);

    // Add bound_shift to the bounds and remove a bound if it is now trivial.
    if (constraint.has_upper_bound()) {
      constraint.set_upper_bound(constraint.upper_bound() +
                                 bound_shift.value());
      if (max_value <= constraint.upper_bound()) {
        constraint.clear_upper_bound();
      }
    }
    if (constraint.has_lower_bound()) {
      constraint.set_lower_bound(constraint.lower_bound() +
                                 bound_shift.value());
      // This is because ApplyLiteralMapping make all coefficient positive.
      if (constraint.lower_bound() <= 0) {
        constraint.clear_lower_bound();
      }
    }

    // If the constraint is always true, we just leave it empty.
    if (constraint.has_lower_bound() || constraint.has_upper_bound()) {
      for (const LiteralWithCoeff& entry : cst) {
        constraint.add_literals(entry.literal.SignedValue());
        constraint.add_coefficients(entry.coefficient.value());
      }
    }
  }

  // Remove empty constraints.
  int new_index = 0;
  const int num_constraints = problem->constraints_size();
  for (int i = 0; i < num_constraints; ++i) {
    if (!(problem->constraints(i).literals_size() == 0)) {
      problem->mutable_constraints()->SwapElements(i, new_index);
      ++new_index;
    }
  }
  problem->mutable_constraints()->DeleteSubrange(new_index,
                                                 num_constraints - new_index);

  // Computes the new number of variables and set it.
  int num_vars = 0;
  for (LiteralIndex index : mapping) {
    if (index >= 0) {
      num_vars = std::max(num_vars, Literal(index).Variable().value() + 1);
    }
  }
  problem->set_num_variables(num_vars);

  // TODO(user): The names is currently all scrambled. Do something about it
  // so that non-fixed variables keep their names.
  problem->mutable_var_names()->DeleteSubrange(
      num_vars, problem->var_names_size() - num_vars);
}

// A simple preprocessing step that does basic probing and removes the
// equivalent literals.
void ProbeAndSimplifyProblem(SatPostsolver* postsolver,
                             LinearBooleanProblem* problem) {
  // TODO(user): expose the number of iterations as a parameter.
  for (int iter = 0; iter < 6; ++iter) {
    SatSolver solver;
    if (!LoadBooleanProblem(*problem, &solver)) {
      LOG(INFO) << "UNSAT when loading the problem.";
    }

    absl::StrongVector<LiteralIndex, LiteralIndex> equiv_map;
    ProbeAndFindEquivalentLiteral(&solver, postsolver, /*drat_writer=*/nullptr,
                                  &equiv_map);

    // We can abort if no information is learned.
    if (equiv_map.empty() && solver.LiteralTrail().Index() == 0) break;

    if (equiv_map.empty()) {
      const int num_literals = 2 * solver.NumVariables();
      for (LiteralIndex index(0); index < num_literals; ++index) {
        equiv_map.push_back(index);
      }
    }

    // Fix fixed variables in the equivalence map and in the postsolver.
    solver.Backtrack(0);
    for (int i = 0; i < solver.LiteralTrail().Index(); ++i) {
      const Literal l = solver.LiteralTrail()[i];
      equiv_map[l.Index()] = kTrueLiteralIndex;
      equiv_map[l.NegatedIndex()] = kFalseLiteralIndex;
      postsolver->FixVariable(l);
    }

    // Remap the variables into a dense set. All the variables for which the
    // equiv_map is not the identity are no longer needed.
    BooleanVariable new_var(0);
    absl::StrongVector<BooleanVariable, BooleanVariable> var_map;
    for (BooleanVariable var(0); var < solver.NumVariables(); ++var) {
      if (equiv_map[Literal(var, true).Index()] == Literal(var, true).Index()) {
        var_map.push_back(new_var);
        ++new_var;
      } else {
        var_map.push_back(BooleanVariable(-1));
      }
    }

    // Apply the variable mapping.
    postsolver->ApplyMapping(var_map);
    for (LiteralIndex index(0); index < equiv_map.size(); ++index) {
      if (equiv_map[index] >= 0) {
        const Literal l(equiv_map[index]);
        const BooleanVariable image = var_map[l.Variable()];
        CHECK_NE(image, BooleanVariable(-1));
        equiv_map[index] = Literal(image, l.IsPositive()).Index();
      }
    }
    ApplyLiteralMappingToBooleanProblem(equiv_map, problem);
  }
}

}  // namespace sat
}  // namespace operations_research


text:
Quickly install (or replace) **only** the dotfiles using `curl` and `tar`:

```bash
# Navigate to your project's root:
$ cd foo/
# Backup existing dotfiles (optional):
$ mv .editorconfig .editorconfig_bak && mv .gitattributes .gitattributes_bak && mv .gitignore .gitignore_bak
# Install dotfiles:
$ curl -#L https://github.com/mhulse/gh-boiler/tarball/master | tar -xzv --strip-components 1 --include=*/{.editorconfig,.gitattributes,.gitignore} --exclude=*/**/*
```

Boilerplate `README.md` verbiage follows …

---

# Lorem Ipsum

[![ScreenShot](top.png)](#)

**A quick brown fox jumps over the lazy dog.**

## Table of contents

- [About](#about)
	- [Subsection A](#subsection-a)
	- [Subsection B](#subsection-b)
	- [Subsection C](#subsection-c)
	- [Subsection D](#subsection-d)
	- [Subsection E](#subsection-e)
- [Demonstration](#demonstration)
- [Installation](#installation)
- [Links](#links)
	- [GitHub](#github)
	- [Markdown](#markdown)
	- [Licensing](#licensing)
- [Contributing](#contributing)
- [Feedback](#feedback)
- [Release history](#release-history)
- [LEGAL](#legal)

## About [](#table-of-contents)

A quick brown fox jumps over the lazy dog.

### Subsection A

Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Aenean commodo ligula eget dolor. Aenean massa.

### Subsection B

Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus.

### Subsection C

Nullam quis ante. Etiam sit amet orci eget eros faucibus tincidunt. Duis leo. Sed fringilla mauris sit amet nibh. Donec sodales sagittis magna.

### Subsection D

Nam eget dui. Etiam rhoncus. Maecenas tempus, tellus eget condimentum rhoncus, sem quam semper libero, sit amet adipiscing sem neque sed ipsum.

### Subsection E

Nam quam nunc, blandit vel, luctus pulvinar, hendrerit id, lorem. Maecenas nec odio et ante tincidunt tempus. Donec vitae sapien ut libero venenatis faucibus.

## Demonstration [](#table-of-contents)

Click or scan:

DEVELOPMENT | PRODUCTION
:-: | :-:
[![qr code](http://chart.apis.google.com/chart?cht=qr&chl=https://github.com/user/repo&chs=240x240)](http://user.github.io/repo/dev/) | [![qr code](http://chart.apis.google.com/chart?cht=qr&chl=https://github.com/user/repo/&chs=240x240)](http://user.github.io/repo/prod/)

## Installation [](#table-of-contents)

A quick brown fox jumps over the lazy dog.

1. Lorem ipsum dolor sit amet.
1. Phasellus viverra nulla ut metus varius laoreet.
1. Aenean vulputate eleifend tellus.
1. Donec vitae sapien ut libero venenatis faucibus.

## Links [](#table-of-contents)

### GitHub

* [GitHub help](https://help.github.com/)
	* [Setting up a custom domain with Pages](https://help.github.com/articles/setting-up-a-custom-domain-with-pages)
	* [GitHub Pages](https://help.github.com/categories/20/articles)
* [The GitHub Blog](https://github.com/blog/):
	* [New Features](https://github.com/blog/category/ship)
	* [Broadcasts](https://github.com/blog/broadcasts)
* [Apps](http://git-scm.com/downloads/guis):
	* [GitHub Mobile](http://mobile.github.com/)
	* [GitHub for Mac](http://mac.github.com/)
	* [GitHub for Windows](http://windows.github.com/)

### Markdown

* [GitHub Flavored Markdown](http://github.github.com/github-flavored-markdown/)
* [Markdown: Syntax](http://daringfireball.net/projects/markdown/syntax)
* [Markdown Cheatsheet](https://github.com/adam-p/markdown-here/wiki/Markdown-Cheatsheet)

### Licensing

* [Choose an OSS License](http://choosealicense.com/)
* [Pick a License, Any License](http://www.codinghorror.com/blog/2007/04/pick-a-license-any-license.html)

## Contributing [](#table-of-contents)

Please read the [CONTRIBUTING.md](CONTRIBUTING.md).

## Feedback [](#table-of-contents)

[Bugs? Constructive feedback? Questions?](https://github.com/mhulse/gh-boiler/issues/new?title=Nymphs%20blitz%20quick%20vex%20dwarf%20jog!&body=A%20very%20bad%20quack%20might%20jinx%20zippy%20fowls%20…)

## Changelog [](#table-of-contents)

* [v1.0.0 milestones](https://github.com/mhulse/gh-boiler/issues?direction=desc&milestone=1&page=1&sort=updated&state=closed)

## [Release history](https://github.com/mhulse/gh-boiler/releases) [](#table-of-contents)

* 2013-01-01   [v1.0.0](https://github.com/mhulse/gh-boiler/releases/tag/v1.0.0)   Lorem ipsum dolor sit amet.
* 1970-01-01   [v0.1.0](https://github.com/mhulse/gh-boiler/releases/tag/v0.1.0)   Lorem ipsum dolor sit amet.

---

Copyright © YYYY-YY [First Last](#). **All rights reserved.**

Unauthorized use and/or duplication of this material, without express and written permission from the owner, is strictly prohibited.

---

#### LEGAL

Copyright © YYYY-YY [First Last](#).

Licensed under the Apache License, Version 2.0 (the "License"); you may not use this work except in compliance with the License. You may obtain a copy of the License in the LICENSE file, or at:

[http://www.apache.org/licenses/LICENSE-2.0](http://www.apache.org/licenses/LICENSE-2.0)

Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License.

redpajama_set_name: RedPajamaGithub


text:
package org.apache.directory.server.config.beans;

import org.apache.directory.server.config.ConfigurationElement;

/**
 * Configuration bean of an authenticator implementation.
 *
 * @author Apache Directory Project
 */
public class AuthenticatorImplBean extends AuthenticatorBean
{
    /** the fully qualified class name of the authenticator implementation */
    @ConfigurationElement(attributeType = "ads-authenticatorClass")
    private String authenticatorClass;

    /**
     * Creates a new instance of AuthenticatorImplBean.
     */
    public AuthenticatorImplBean()
    {
    }

    /**
     * @return the authenticatorClass
     */
    public String getAuthenticatorClass()
    {
        return authenticatorClass;
    }

    /**
     * @param authenticatorClass the authenticatorClass to set
     */
    public void setAuthenticatorClass( String authenticatorClass )
    {
        this.authenticatorClass = authenticatorClass;
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public String toString()
    {
        return "AuthenticatorImplBean [authenticatorClass=" + authenticatorClass + "]";
    }
}


text:
package harmonyintegration.webserver;

import harmonyintegration.harmony.HarmonyHub;
import net.sourceforge.sorb.Service;
import net.sourceforge.spinnerule.*;

import java.io.IOException;
import java.net.URI;

public final class SpinneruleHttpSwitcherOfferService implements Service<HttpSwitcherOffer> {
    private final SpinneruleService spinneruleService;

    public SpinneruleHttpSwitcherOfferService(final HarmonyHub harmonyHub, final int port) throws IOException {
        spinneruleService = new SpinneruleService(port, new Auditor() {
            @Override
            public void successfullyHandledRequest(final URI requestURI, final String protocol, final String requestMethod, final RequestHeaders requestHeaders, final String clientIpAddress, final int responseCode, final long responseLengthBytes) {
                System.out.println("requestURI = " + requestURI);
                System.out.println("protocol = " + protocol);
                System.out.println("requestMethod = " + requestMethod);
                System.out.println("requestHeaders = " + requestHeaders);
                System.out.println("clientIpAddress = " + clientIpAddress);
                System.out.println("responseCode = " + responseCode);
                System.out.println("responseLengthBytes = " + responseLengthBytes);
            }

            @Override
            public void failedHandlingRequest(final IOException e) {
                e.printStackTrace();
            }

            @Override
            public void failedHandlingRequest(final RuntimeException e) {
                e.printStackTrace();
            }
        }, Context.context("/allOff", request -> {
            harmonyHub.sendAllOff();
            return Response.ok(BodiedContent.text("Switched off"));
        }), Context.context("/", request -> Response.notFound(EmptyContent.emptyContent())));
    }

    @Override
    public HttpSwitcherOffer start() {
        final Spinnerule spinnerule = spinneruleService.start();
        return spinnerule::close;
    }
}


text:
<?php

 /**
   *
   */
require_once(__CA_LIB_DIR__.'/core/BaseRelationshipModel.php');

BaseModel::$s_ca_models_definitions['ca_places_x_storage_locations'] = array(
 	'NAME_SINGULAR' 	=> _t('places ⇔ storage locations relationship'),
 	'NAME_PLURAL' 		=> _t('places ⇔ storage locations relationships'),
 	'FIELDS' 			=> array(
 		'relation_id' => array(
				'FIELD_TYPE' => FT_NUMBER, 'DISPLAY_TYPE' => DT_HIDDEN,
				'IDENTITY' => true, 'DISPLAY_WIDTH' => 10, 'DISPLAY_HEIGHT' => 1,
				'IS_NULL' => false,
				'DEFAULT' => '',
				'LABEL' => 'Relation id', 'DESCRIPTION' => 'Identifier for Relation'
		),
		'place_id' => array(
				'FIELD_TYPE' => FT_NUMBER, 'DISPLAY_TYPE' => DT_FIELD,
				'DISPLAY_WIDTH' => 10, 'DISPLAY_HEIGHT' => 1,
				'IS_NULL' => false,
				'DEFAULT' => '',
				'LABEL' => 'Place id', 'DESCRIPTION' => 'Identifier for place'
		),
		'type_id' => array(
				'FIELD_TYPE' => FT_NUMBER, 'DISPLAY_TYPE' => DT_FIELD,
				'DISPLAY_WIDTH' => 10, 'DISPLAY_HEIGHT' => 1,
				'IS_NULL' => false,
				'DEFAULT' => '',
				'LABEL' => 'Type id', 'DESCRIPTION' => 'Identifier for Type',
				'BOUNDS_VALUE' => array(0,65535)
		),
		'location_id' => array(
				'FIELD_TYPE' => FT_NUMBER, 'DISPLAY_TYPE' => DT_FIELD,
				'DISPLAY_WIDTH' => 10, 'DISPLAY_HEIGHT' => 1,
				'IS_NULL' => false,
				'DEFAULT' => '',
				'LABEL' => 'Location id', 'DESCRIPTION' => 'Identifier for Location'
		),
		'source_info' => array(
				'FIELD_TYPE' => FT_TEXT, 'DISPLAY_TYPE' => DT_FIELD,
				'DISPLAY_WIDTH' => 88, 'DISPLAY_HEIGHT' => 15,
				'IS_NULL' => false,
				'DEFAULT' => '',
				'LABEL' => 'Source information', 'DESCRIPTION' => 'Source information'
		),
		'effective_date' => array(
				'FIELD_TYPE' => FT_HISTORIC_DATERANGE, 'DISPLAY_TYPE' => DT_FIELD,
				'DISPLAY_WIDTH' => 40, 'DISPLAY_HEIGHT' => 1,
				'IS_NULL' => true,
				'DEFAULT' => '',
				'START' => 'sdatetime', 'END' => 'edatetime',
				'LABEL' => _t('Effective dates'), 'DESCRIPTION' => _t('Period of time for which this relationship was in effect. This is an option qualification for the relationship. If left blank, this relationship is implied to have existed for as long as the related items have existed.')
		),
		'rank' => array(
				'FIELD_TYPE' => FT_NUMBER, 'DISPLAY_TYPE' => DT_OMIT,
				'DISPLAY_WIDTH' => 10, 'DISPLAY_HEIGHT' => 1,
				'IS_NULL' => false,
				'DEFAULT' => '',
				'LABEL' => _t('Sort order'), 'DESCRIPTION' => _t('The relative priority of the relationship when displayed in a list with other relationships. Lower numbers indicate higher priority.')
		)
 	)
);

class ca_places_x_storage_locations extends BaseRelationshipModel {
	# ---------------------------------
	# --- Object attribute properties
	# ---------------------------------
	# Describe structure of content object's properties - eg. database fields and their
	# associated types, what modes are supported, et al.
	#

	# ------------------------------------------------------
	# --- Basic object parameters
	# ------------------------------------------------------
	# what table does this class represent?
	protected $TABLE = 'ca_places_x_storage_locations';

	# what is the primary key of the table?
	protected $PRIMARY_KEY = 'relation_id';

	# ------------------------------------------------------
	# --- Properties used by standard editing scripts
	#
	# These class properties allow generic scripts to properly display
	# records from the table represented by this class
	#
	# ------------------------------------------------------

	# Array of fields to display in a listing of records from this table
	protected $LIST_FIELDS = array('source_info');

	# When the list of "list fields" above contains more than one field,
	# the LIST_DELIMITER text is displayed between fields as a delimiter.
	# This is typically a comma or space, but can be any string you like
	protected $LIST_DELIMITER = ' ';

	# What you'd call a single record from this table (eg. a "person")
	protected $NAME_SINGULAR;

	# What you'd call more than one record from this table (eg. "people")
	protected $NAME_PLURAL;

	# List of fields to sort listing of records by; you can use
	# SQL 'ASC' and 'DESC' here if you like.
	protected $ORDER_BY = array('source_info');

	# Maximum number of record to display per page in a listing
	protected $MAX_RECORDS_PER_PAGE = 20;

	# How do you want to page through records in a listing: by number pages ordered
	# according to your setting above? Or alphabetically by the letters of the first
	# LIST_FIELD?
	protected $PAGE_SCHEME = 'alpha'; # alpha [alphabetical] or num [numbered pages; default]

	# If you want to order records arbitrarily, add a numeric field to the table and place
	# its name here. The generic list scripts can then use it to order table records.
	protected $RANK = 'rank';

	# ------------------------------------------------------
	# Hierarchical table properties
	# ------------------------------------------------------
	protected $HIERARCHY_TYPE				=	null;
	protected $HIERARCHY_LEFT_INDEX_FLD 	= 	null;
	protected $HIERARCHY_RIGHT_INDEX_FLD 	= 	null;
	protected $HIERARCHY_PARENT_ID_FLD		=	null;
	protected $HIERARCHY_DEFINITION_TABLE	=	null;
	protected $HIERARCHY_ID_FLD				=	null;
	protected $HIERARCHY_POLY_TABLE			=	null;

	# ------------------------------------------------------
	# Change logging
	# ------------------------------------------------------
	protected $UNIT_ID_FIELD = null;
	protected $LOG_CHANGES_TO_SELF = false;
	protected $LOG_CHANGES_USING_AS_SUBJECT = array(
		"FOREIGN_KEYS" => array(
			'place_id', 'location_id'
		),
		"RELATED_TABLES" => array(

		)
	);

	# ------------------------------------------------------
	# --- Relationship info
	# ------------------------------------------------------
	protected $RELATIONSHIP_LEFT_TABLENAME = 'ca_places';
	protected $RELATIONSHIP_RIGHT_TABLENAME = 'ca_storage_locations';
	protected $RELATIONSHIP_LEFT_FIELDNAME = 'place_id';
	protected $RELATIONSHIP_RIGHT_FIELDNAME = 'location_id';
	protected $RELATIONSHIP_TYPE_FIELDNAME = 'type_id';

	# ------------------------------------------------------
	# $FIELDS contains information about each field in the table. The order in which the fields
	# are listed here is the order in which they will be returned using getFields()
	#
	# There are number of types of information that can be set here, some having to do with the
	# underlying specifics of the field (eg. is it NULL?) and others having to do with input
	# validation (eg. must be between 50 and 100) or presentation in an HTML form (eg. show it as
	# a text field 30 characters wide). See the documentation for BaseRelationshipModel.php for a complete list
	# of field specifiers.
	protected $FIELDS;

	# ------------------------------------------------------
	# --- Constructor
	#
	# This is a function called when a new instance of this object is created. This
	# standard constructor supports three calling modes:
	#
	# 1. If called without parameters, simply creates a new, empty objects object
	# 2. If called with a single, valid primary key value, creates a new objects object and loads
	#    the record identified by the primary key value
	#
	# ------------------------------------------------------
	public function __construct($pn_id=null) {
		parent::__construct($pn_id);	# call superclass constructor
	}
	# ------------------------------------------------------
}
?>


text:
/**
 * You can customize the initial state of the module from the editor initialization
 * ```js
 * const editor = grapesjs.init({
 *  ....
 *  pageManager: {
 *    pages: [
 *      {
 *        id: 'page-id',
 *        styles: `.my-class { color: red }`, // or a JSON of styles
 *        component: '<div class="my-class">My element</div>', // or a JSON of components
 *      }
 *   ]
 *  },
 * })
 * ```
 *
 * Once the editor is instantiated you can use its API. Before using these methods you should get the module from the instance
 *
 * ```js
 * const pageManager = editor.Pages;
 * ```
 *
 * ## Available Events
 * * `page:add` - Added new page. The page is passed as an argument to the callback
 * * `page:remove` - Page removed. The page is passed as an argument to the callback
 * * `page:select` - New page selected. The newly selected page and the previous one, are passed as arguments to the callback
 * * `page:update` - Page updated. The updated page and the object containing changes are passed as arguments to the callback
 * * `page` - Catch-all event for all the events mentioned above. An object containing all the available data about the triggered event is passed as an argument to the callback
 *
 * ## Methods
 * * [add](#add)
 * * [get](#get)
 * * [getAll](#getall)
 * * [getAllWrappers](#getallwrappers)
 * * [getMain](#getmain)
 * * [remove](#remove)
 * * [select](#select)
 * * [getSelected](#getselected)
 *
 * [Page]: page.html
 * [Component]: component.html
 *
 * @module Pages
 */

import { isString, bindAll, unique, flatten } from 'underscore';
import { createId } from '../utils/mixins';
import { Model, Module } from '../abstract';
import { ItemManagerModule, ModuleConfig } from '../abstract/Module';
import Pages from './model/Pages';
import Page from './model/Page';
import EditorModel from '../editor/model/Editor';

export const evAll = 'page';
export const evPfx = `${evAll}:`;
export const evPageSelect = `${evPfx}select`;
export const evPageSelectBefore = `${evPageSelect}:before`;
export const evPageUpdate = `${evPfx}update`;
export const evPageAdd = `${evPfx}add`;
export const evPageAddBefore = `${evPageAdd}:before`;
export const evPageRemove = `${evPfx}remove`;
export const evPageRemoveBefore = `${evPageRemove}:before`;
const chnSel = 'change:selected';
const typeMain = 'main';
const events = {
  all: evAll,
  select: evPageSelect,
  selectBefore: evPageSelectBefore,
  update: evPageUpdate,
  add: evPageAdd,
  addBefore: evPageAddBefore,
  remove: evPageRemove,
  removeBefore: evPageRemoveBefore,
};

export interface PageManagerConfig extends ModuleConfig {
  pages?: any[];
}

export default class PageManager extends ItemManagerModule<PageManagerConfig, Pages> {
  storageKey = 'pages';

  get pages() {
    return this.all;
  }

  model: Model;

  /**
   * Get all pages
   * @name getAll
   * @function
   * @returns {Array<[Page]>}
   * @example
   * const arrayOfPages = pageManager.getAll();
   */

  /**
   * Initialize module
   * @param {Object} config Configurations
   * @private
   */
  constructor(em: EditorModel) {
    super(em, 'PageManager', new Pages([], em), events);
    bindAll(this, '_onPageChange');
    const model = new Model({ _undo: true } as any);
    this.model = model;
    this.pages.on('reset', coll => coll.at(0) && this.select(coll.at(0)));
    this.pages.on('all', this.__onChange, this);
    model.on(chnSel, this._onPageChange);

    return this;
  }

  __onChange(event: string, page: Page, coll: Pages, opts?: any) {
    const options = opts || coll;
    this.em.trigger(evAll, { event, page, options });
  }

  onLoad() {
    const { pages } = this;
    const opt = { silent: true };
    pages.add(this.config.pages?.map(page => new Page(page, { em: this.em, config: this.config })) || [], opt);
    const mainPage = !pages.length ? this.add({ type: typeMain }, opt) : this.getMain();
    mainPage && this.select(mainPage, opt);
  }

  _onPageChange(m: any, page: Page, opts: any) {
    const { em } = this;
    const lm = em.get('LayerManager');
    const mainComp = page.getMainComponent();
    lm && mainComp && lm.setRoot(mainComp);
    em.trigger(evPageSelect, page, m.previous('selected'));
    this.__onChange(chnSel, page, opts);
  }

  postLoad() {
    const { em, model } = this;
    const um = em.get('UndoManager');
    um && um.add(model);
    um && um.add(this.pages);
  }

  /**
   * Add new page
   * @param {Object} props Page properties
   * @param {Object} [opts] Options
   * @returns {[Page]}
   * @example
   * const newPage = pageManager.add({
   *  id: 'new-page-id', // without an explicit ID, a random one will be created
   *  styles: `.my-class { color: red }`, // or a JSON of styles
   *  component: '
My element
', // or a JSON of components
   * });
   */
  add(
    props: any, //{ id?: string; styles: string; component: string },
    opts: any = {}
  ) {
    const { em } = this;
    props.id = props.id || this._createId();
    const add = () => {
      const page = this.pages.add(new Page(props, { em: this.em, config: this.config }), opts);
      opts.select && this.select(page);
      return page;
    };
    !opts.silent && em.trigger(evPageAddBefore, props, add, opts);
    return !opts.abort && add();
  }

  /**
   * Remove page
   * @param {String|[Page]} page Page or page id
   * @returns {[Page]} Removed Page
   * @example
   * const removedPage = pageManager.remove('page-id');
   * // or by passing the page
   * const somePage = pageManager.get('page-id');
   * pageManager.remove(somePage);
   */
  remove(page: string | Page, opts: any = {}) {
    const { em } = this;
    const pg = isString(page) ? this.get(page) : page;
    const rm = () => {
      pg && this.pages.remove(pg, opts);
      return pg;
    };
    !opts.silent && em.trigger(evPageRemoveBefore, pg, rm, opts);
    return !opts.abort && rm();
  }

  /**
   * Get page by id
   * @param {String} id Page id
   * @returns {[Page]}
   * @example
   * const somePage = pageManager.get('page-id');
   */
  get(id: string) {
    return this.pages.filter(p => p.get(p.idAttribute) === id)[0];
  }

  /**
   * Get main page (the first one available)
   * @returns {[Page]}
   * @example
   * const mainPage = pageManager.getMain();
   */
  getMain() {
    const { pages } = this;
    return pages.filter(p => p.get('type') === typeMain)[0] || pages.at(0);
  }

  /**
   * Get wrapper components (aka body) from all pages and frames.
   * @returns {Array<[Component]>}
   * @example
   * const wrappers = pageManager.getAllWrappers();
   * // Get all `image` components from the project
   * const allImages = wrappers.map(wrp => wrp.findType('image')).flat();
   */
  getAllWrappers() {
    const pages = this.getAll();
    return unique(flatten(pages.map(page => page.getAllFrames().map(frame => frame.getComponent()))));
  }

  /**
   * Change the selected page. This will switch the page rendered in canvas
   * @param {String|[Page]} page Page or page id
   * @returns {this}
   * @example
   * pageManager.select('page-id');
   * // or by passing the page
   * const somePage = pageManager.get('page-id');
   * pageManager.select(somePage);
   */
  select(page: string | Page, opts = {}) {
    const pg = isString(page) ? this.get(page) : page;
    if (pg) {
      this.em.trigger(evPageSelectBefore, pg, opts);
      this.model.set('selected', pg, opts);
    }
    return this;
  }

  /**
   * Get the selected page
   * @returns {[Page]}
   * @example
   * const selectedPage = pageManager.getSelected();
   */
  getSelected() {
    return this.model.get('selected');
  }

  destroy() {
    this.pages.off().reset();
    this.model.stopListening();
    this.model.clear({ silent: true });
    //@ts-ignore
    ['selected', 'model'].map(i => (this[i] = 0));
  }

  store() {
    return this.getProjectData();
  }

  load(data: any) {
    return this.loadProjectData(data, { all: this.pages, reset: true });
  }

  _createId() {
    const pages = this.getAll();
    const len = pages.length + 16;
    const pagesMap = this.getAllMap();
    let id;

    do {
      id = createId(len);
    } while (pagesMap[id]);

    return id;
  }
}


text:
import { inject as service } from '@ember/service';
import Controller, { inject as controller } from '@ember/controller';
import { getOwner } from '@ember/application';

const headers = [
  {
    name:           'state',
    sort:           ['sortState', 'name', 'id'],
    translationKey: 'generic.state',
    width:          125,
  },
  {
    name:           'name',
    searchField:    'displayName',
    sort:           ['displayName', 'id'],
    translationKey: 'clustersPage.cluster.label',
  },
  {
    name:           'provider',
    searchField:    'displayProvider',
    sort:           ['displayProvider', 'name', 'id'],
    translationKey: 'clustersPage.provider.label',
    width:          150,
  },
  {
    name:           'nodes',
    searchField:    'nodes.length',
    sort:           ['nodes.length', 'name', 'id'],
    translationKey: 'clustersPage.nodes.label',
    width:          100,
  },
  {
    name:           'cpu',
    sort:           ['cpuUsage', 'name'],
    searchField:    'cpuUsage',
    translationKey: 'clustersPage.cpu.label',
    width:          100,
  },
  {
    name:           'memory',
    searchField:    'memoryUsage',
    sort:           ['memoryUsage', 'name'],
    translationKey: 'clustersPage.memory.label',
    width:          125,
  }
];

export default Controller.extend({
  modalService:       service('modal'),
  access:             service(),
  scope:              service(),
  settings:           service(),
  prefs:              service(),
  router:             service(),

  application:        controller(),
  queryParams:        ['mode'],
  mode:               'grouped',

  headers,
  extraSearchFields:  ['version.gitVersion'],
  sortBy:             'name',
  searchText:         null,
  bulkActions:        true,

  actions: {
    launchOnCluster(model) {
      let authenticated = getOwner(this).lookup('route:authenticated');

      if (this.get('scope.currentProject.id') === model.get('defaultProject.id')) {
        this.transitionToRoute('authenticated.host-templates', {
          queryParams: {
            clusterId: model.get('id'),
            backTo:    'clusters'
          }
        });
      } else {
        authenticated.send('switchProject', model.get('defaultProject.id'), 'authenticated.host-templates', [model.id, { queryParams: { backTo: 'clusters' } }]);
      }
    },
    useKubernetes(model) {
      let authenticated = getOwner(this).lookup('route:authenticated');

      authenticated.send('switchProject', model.get('defaultProject.id'), 'authenticated.cluster.import', [model.id, { queryParams: { backTo: 'clusters' } }]);
    },
  },
});


text:
@protocol FEUserModel <NSObject, NSCoding>

@property (copy,   nonatomic) NSString *userID; //
@property (copy,   nonatomic) NSString *username; //
@property (copy,   nonatomic) NSString *password; //
@property (strong, nonatomic) NSDate   *updateDate; //
@property (strong, nonatomic) NSDictionary *userInfo; //

@end


text:
package com.africastalking.test;

import com.africastalking.*;
import org.junit.Test;

import static org.junit.Assert.assertEquals;

public class AfricasTalkingTest {

    @Test
    public void testInitialization() {
        AfricasTalking.initialize(Fixtures.USERNAME, Fixtures.API_KEY);
        ApplicationService ac1 = AfricasTalking.getService(ApplicationService.class);
        ApplicationService ac2 = AfricasTalking.getService(AfricasTalking.SERVICE_APPLICATION);
        assertEquals(ac1, ac2);
    }
}


text:
<?php

namespace Encyclopedia\LibraryBundle\Form;

use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolverInterface;

class PersonsAliasType extends AbstractType
{
        /**
     * @param FormBuilderInterface $builder
     * @param array $options
     */
    public function buildForm(FormBuilderInterface $builder, array $options)
    {
        $builder
            ->add('name')
            ->add('id_person', 'entity', array('class' => 'EncyclopediaLibraryBundle:Persons',
                                                'property' => 'name',
                                                'label' => 'Person name'))
        ;
    }

    /**
     * @param OptionsResolverInterface $resolver
     */
    public function setDefaultOptions(OptionsResolverInterface $resolver)
    {
        $resolver->setDefaults(array(
            'data_class' => 'Encyclopedia\LibraryBundle\Entity\PersonsAlias'
        ));
    }

    /**
     * @return string
     */
    public function getName()
    {
        return 'encyclopedia_LibraryBundle_personsalias';
    }
}


text:
import random
import csv
with open('points.csv', 'wb') as csvfile:
    writer = csv.writer(csvfile, delimiter=' ',quotechar='|', quoting=csv.QUOTE_MINIMAL)

    row = []
    for i in range(1000):
        row.append(random.randrange(-2000,1000))
        row.append(random.randrange(20,1000))
        row.append(random.randrange(0,3))
        writer.writerow(row)
        row = []


text:
require 'faraday'

module Requests::Submissions
  class DigitizeItem < Service
    def initialize(submission, service_type: 'digitize')
      super
      @service_types = { digitize: { cited_pages: 'COVID-19 Campus Closure', note: 'Digitization Request' },
                         marquand_edd: { cited_pages: 'Marquand EDD', note: 'Digitization Request Marquand Item' },
                         clancy_edd: { cited_pages: 'Marquand Clancy EDD', note: 'Digitization Request Marquand Item at Clancy' },
                         clancy_unavailable_edd: { cited_pages: 'Marquand Clancy UNAVAIL EDD', note: 'Digitization Request Marquand Item at Clancy (Unavailable)' } }
    end

    def handle
      params = @service_types[service_type.to_sym]
      items = @submission.filter_items_by_service(service_type)
      items.each do |item|
        item_status = handle_item(item: item, **params)
        if item_status.present?
          item["transaction_number"] = item_status["TransactionNumber"].to_s
          @sent << item_status unless item_status.blank?
        end
      end
      return false if @errors.present?
    end

    def submitted
      @sent
    end

    private

      def handle_item(item:, note:, cited_pages:)
        client = Requests::IlliadTransactionClient.new(patron: @submission.patron, metadata_mapper: Requests::IlliadMetadata::ArticleExpress.new(patron: @submission.patron, bib: @submission.bib, item: item, note: note, cited_pages: cited_pages))
        transaction = client.create_request
        errors << { type: 'digitize', bibid: @submission.bib, item: item, user_name: @submission.user_name, barcode: @submission.user_barcode, error: "Invalid Illiad Patron" } if transaction.blank?
        if transaction == "DISAVOWED"
          errors << { type: 'digitize', bibid: @submission.bib, item: item, user_name: @submission.user_name, barcode: @submission.user_barcode, error: "You no longer have an active account and may not make digitization requests." }
          transaction = nil
        end
        transaction
      end
  end
end


text:
<?php

/**
 * @namespace
 */
namespace ZendTest\Validate\File;
use Zend\Validator\File;
use Zend\Validator;

// Call Zend_Validate_File_SizeTest::main() if this source file is executed directly.
if (!defined("PHPUnit_MAIN_METHOD")) {
    define("PHPUnit_MAIN_METHOD", "Zend_Validate_File_SizeTest::main");
}

/**
 * Test helper
 */

/**
 * @see Zend_Validate_File_Size
 */

/**
 * @category   Zend
 * @package    Zend_Validate_File
 * @subpackage UnitTests
 * @copyright  Copyright (c) 2005-2010 Zend Technologies USA Inc. (http://www.zend.com)
 * @license    http://framework.zend.com/license/new-bsd     New BSD License
 * @group      Zend_Validate
 */
class SizeTest extends \PHPUnit_Framework_TestCase
{
    /**
     * Runs the test methods of this class.
     *
     * @return void
     */
    public static function main()
    {
        $suite  = new \PHPUnit_Framework_TestSuite("Zend_Validate_File_SizeTest");
        $result = \PHPUnit_TextUI_TestRunner::run($suite);
    }

    /**
     * Ensures that the validator follows expected behavior
     *
     * @return void
     */
    public function testBasic()
    {
        $valuesExpected = array(
            array(array('min' => 0, 'max' => 10000), true),
            array(array('min' => 0, 'max' => '10 MB'), true),
            array(array('min' => '4B', 'max' => '10 MB'), true),
            array(array('min' => 0, 'max' => '10MB'), true),
            array(array('min' => 0, 'max' => '10  MB'), true),
            array(794, true),
            array(array('min' => 794), true),
            array(array('min' => 0, 'max' => 500), false),
            array(500, false),
        );

        foreach ($valuesExpected as $element) {
            $options = array_shift($element);
            $value   = array_shift($element);
            $validator = new File\Size($options);
            $this->assertEquals(
                $value,
                $validator->isValid(__DIR__ . '/_files/testsize.mo'),
                "Tested " . var_export($value, 1) . " against options " . var_export($options, 1)
            );
        }
    }

    /**
     * Ensures that getMin() returns expected value
     *
     * @return void
     */
    public function testGetMin()
    {
        $validator = new File\Size(array('min' => 1, 'max' => 100));
        $this->assertEquals('1B', $validator->getMin());

        try {
            $validator = new File\Size(array('min' => 100, 'max' => 1));
            $this->fail("Missing exception");
        } catch (Validator\Exception $e) {
            $this->assertContains("greater than or equal", $e->getMessage());
        }

        $validator = new File\Size(array('min' => 1, 'max' => 100, 'bytestring' => false));
        $this->assertEquals(1, $validator->getMin());
    }

    /**
     * Ensures that setMin() returns expected value
     *
     * @return void
     */
    public function testSetMin()
    {
        $validator = new File\Size(array('min' => 1000, 'max' => 10000));
        $validator->setMin(100);
        $this->assertEquals('100B', $validator->getMin());

        try {
            $validator->setMin(20000);
            $this->fail("Missing exception");
        } catch (Validator\Exception $e) {
            $this->assertContains("less than or equal", $e->getMessage());
        }

        $validator = new File\Size(array('min' => 1000, 'max' => 10000, 'bytestring' => false));
        $validator->setMin(100);
        $this->assertEquals(100, $validator->getMin());
    }

    /**
     * Ensures that getMax() returns expected value
     *
     * @return void
     */
    public function testGetMax()
    {
        $validator = new File\Size(array('min' => 1, 'max' => 100, 'bytestring' => false));
        $this->assertEquals(100, $validator->getMax());

        try {
            $validator = new File\Size(array('min' => 100, 'max' => 1));
            $this->fail("Missing exception");
        } catch (Validator\Exception $e) {
            $this->assertContains("greater than or equal", $e->getMessage());
        }

        $validator = new File\Size(array('min' => 1, 'max' => 100000));
        $this->assertEquals('97.66kB', $validator->getMax());

        $validator = new File\Size(2000);
        $this->assertEquals('1.95kB', $validator->getMax());
    }

    /**
     * Ensures that setMax() returns expected value
     *
     * @return void
     */
    public function testSetMax()
    {
        $validator = new File\Size(array('max' => 0, 'bytestring' => true));
        $this->assertEquals('0B', $validator->getMax());

        $validator->setMax(1000000);
        $this->assertEquals('976.56kB', $validator->getMax());

        $validator->setMin(100);
        $this->assertEquals('976.56kB', $validator->getMax());

        $validator->setMax('100 AB');
        $this->assertEquals('100B', $validator->getMax());

        $validator->setMax('100 kB');
        $this->assertEquals('100kB', $validator->getMax());

        $validator->setMax('100 MB');
        $this->assertEquals('100MB', $validator->getMax());

        $validator->setMax('1 GB');
        $this->assertEquals('1GB', $validator->getMax());

        $validator->setMax('0.001 TB');
        $this->assertEquals('1.02GB', $validator->getMax());

        $validator->setMax('0.000001 PB');
        $this->assertEquals('1.05GB', $validator->getMax());

        $validator->setMax('0.000000001 EB');
        $this->assertEquals('1.07GB', $validator->getMax());

        $validator->setMax('0.000000000001 ZB');
        $this->assertEquals('1.1GB', $validator->getMax());

        $validator->setMax('0.000000000000001 YB');
        $this->assertEquals('1.13GB', $validator->getMax());
    }

    /**
     * Ensures that the validator returns size infos
     *
     * @return void
     */
    public function testFailureMessage()
    {
        $validator = new File\Size(array('min' => 9999, 'max' => 10000));
        $this->assertFalse($validator->isValid(__DIR__ . '/_files/testsize.mo'));
        $messages = $validator->getMessages();
        $this->assertContains('9.76kB', current($messages));
        $this->assertContains('794B', current($messages));

        $validator = new File\Size(array('min' => 9999, 'max' => 10000, 'bytestring' => false));
        $this->assertFalse($validator->isValid(__DIR__ . '/_files/testsize.mo'));
        $messages = $validator->getMessages();
        $this->assertContains('9999', current($messages));
        $this->assertContains('794', current($messages));
    }
}

// Call Zend_Validate_File_SizeTest::main() if this source file is executed directly.
if (PHPUnit_MAIN_METHOD == "Zend_Validate_File_SizeTest::main") {
    \Zend_Validate_File_SizeTest::main();
}


text:
<bill session="115" type="h" number="1994" updated="2017-09-12T21:45:18Z">
  <state datetime="2017-04-06">REFERRED</state>
  <status>
    <introduced datetime="2017-04-06"/>
  </status>
  <introduced datetime="2017-04-06"/>
  <titles>
    <title type="short" as="introduced">VETERAN Act</title>
    <title type="short" as="introduced">Vocational Education and Training Enhancements for Reintegration Assistance Now Act</title>
    <title type="short" as="introduced">Vocational Education and Training Enhancements for Reintegration Assistance Now Act</title>
    <title type="official" as="introduced">To direct the Secretary of Veterans Affairs to make improvements to the information technology system of the Veterans Benefits Administration of the Department of Veterans Affairs, and for other purposes.</title>
    <title type="display">VETERAN Act</title>
  </titles>
  <sponsor bioguide_id="B001257"/>
  <cosponsors/>
  <actions>
    <action datetime="2017-04-06">
      <text>Introduced in House</text>
    </action>
    <action datetime="2017-04-06" state="REFERRED">
      <text>Referred to the House Committee on Veterans' Affairs.</text>
    </action>
    <action datetime="2017-04-07">
      <text>Referred to the Subcommittee on Economic Opportunity.</text>
    </action>
  </actions>
  <committees>
    <committee subcommittee="" code="HSVR" name="House Veterans' Affairs" activity="Referral"/>
    <committee subcommittee="Economic Opportunity" code="HSVR10" name="House Veterans' Affairs" activity="Referral"/>
  </committees>
  <relatedbills>
    <bill type="h" session="115" relation="unknown" number="3218"/>
  </relatedbills>
  <subjects>
    <term name="Armed forces and national security"/>
    <term name="Administrative remedies"/>
    <term name="Computers and information technology"/>
    <term name="Congressional oversight"/>
    <term name="Department of Veterans Affairs"/>
    <term name="Student aid and college costs"/>
    <term name="Veterans' education, employment, rehabilitation"/>
  </subjects>
  <amendments/>
  <summary date="2017-04-06T04:00:00Z" status="Introduced in House">Vocational Education and Training Enhancements for Reintegration Assistance Now Act or the VETERAN Act

This bill directs the Department of Veterans Affairs to make changes to the Veterans Benefits Administration's information technology system to ensure that: (1) all original and supplemental claims for Post-9/11 educational assistance are adjudicated electronically, and (2) rules-based processing is used to make decisions with respect to such claims with little human intervention.</summary>
  <committee-reports/>
</bill>


text:
/* author: M@Campbell
 * 10/20/2015
 *
 * Views for any page that needs special controls.
*/

// Parent view for all the page controls.
var ParentPageControlView = Backbone.View.extend({
    /* - initialize()
     * - render()
     * - derender()
     *
     * - loadControls() : Customize this function for each page if you want.
     */
    initialize: function() {
        'use strict';
        _.bindAll(this, 'render', 'derender', 'click');
    },
    events: {
        'click span': 'click'
    },
    // this template will loop through each of the parameters defined in the
    // instantiaed model and create a  tag with an id of the first index
    // and a the tag contents with the second index.
    template: _.template('<% _.each(params, function(item) { %> <span id="<%= item[0] %>"><%= item[1] %><% }) %>'),
    render: function() {
        'use strict';
        if (this.model) { this.$el.html(this.template(this.model.toJSON())); } else
            { this.$el.html(this.template()); }
        // for now, this is in the parent view.  If it doesn't seem to be that common
        // we can move it to a child view's render function.  This is basically
        // just a place holder for additional searching that isn't added to
        // the search bar.
        this.$el.prepend('

');
        return this;
    },
    derender: function() {
        'use strict';
        this.remove();
        this.unbind();
        this.model.off();
    },
    click: function() {

        // placeholder for children
        alert("You have not defined the click method yet for this page\'s controls!");
    }
});

var DataCatalogPageControlView = ParentPageControlView.extend({
    click: function(e) {
        'use strict';

        // define variables up top for SPEED.
        var index, hiddenSearch = this.hiddenSearch || [];

        // lets start by figuring out of the button has already be activated
        // or not . . .
        if (!$('#'+e.target.id).hasClass('active')) {

            // if the target isn't active lets push the search criteria to the
            // hidden search container.
            hiddenSearch.push(e.target.id);
        } else {

            // if the target is already active, lets find it in the hiddenSearch
            // array and then remove it.
            index = hiddenSearch.indexOf(e.target.id);
            if (index > -1) {
                hiddenSearch.splice(index, 1);
            }
        }

        // once that array is all sorted out, lets stick it in the hidden search field that
        // hass been appended to the page.
        $('#hiddenSearch').val(hiddenSearch.join(' '));
        $('#search').trigger('change');
        $('#'+e.target.id).toggleClass('active');

        // we'll need to persist the array, so lets just attach it to this view.
        this.hiddenSearch = hiddenSearch;
    }
});

var TocPageControlView = ParentPageControlView.extend({
    click: function(e) {
        'use strict';

        // simple toggle of DOM elements.
        switch(e.target.id) {
            case 'engToggle':
                $('.eng-item').toggle();
                break;

            case 'metaDataToggle':
                $('.meta-data-item').toggle();
                break;

            case 'refDesToggle':
                $('.ref-des-item').toggle();
                break;
        }

        // toggle the class.
        $('#'+e.target.id).toggleClass('active');
    }
});


text: function foo() { return "foo"; }


text:
from orderdict import orderdict
import output

class FileData(dict):
    def __init__(self, filename):
        self.filename = filename
        fd = file(filename)
        current = []
        for line in fd:
            line = line.strip()
            if line.startswith('>>>'):
                current = []
                self[line[3:]] = current
            else:
                current.append(line)
        fd.close()

class RunData(dict):
    def __init__(self, filename):
        self.filename = filename

    def __getattribute__(self, attr):
        if attr == 'total':
            total = 0.0
            for value in self.itervalues():
                total += value
            return total

        if attr == 'filedata':
            return FileData(self.filename)

        if attr == 'maxsymlen':
            return max([ len(sym) for sym in self.iterkeys() ])

        return super(RunData, self).__getattribute__(attr)

    def display(self, output=None, limit=None, maxsymlen=None):
        if not output:
            import sys
            output = sys.stdout
        elif isinstance(output, str):
            output = file(output, 'w')

        total = float(self.total)

        # swap (string,count) order so we can sort on count
        symbols = [ (count,name) for name,count in self.iteritems() ]
        symbols.sort(reverse=True)
        if limit is not None:
            symbols = symbols[:limit]

        if not maxsymlen:
            maxsymlen = self.maxsymlen

        symbolf = "%-" + str(maxsymlen + 1) + "s %.2f%%"
        for number,name in symbols:
            print >>output, symbolf % (name, 100.0 * (float(number) / total))

class PCData(RunData):
    def __init__(self, filename=None, categorize=None, showidle=True):
        super(PCData, self).__init__(self, filename)

        filedata = self.filedata['PC data']
        for line in filedata:
            (symbol, count) = line.split()
            if symbol == "0x0":
                continue
            count = int(count)

            if categorize is not None:
                category = categorize(symbol)
                if category is None:
                    category = 'other'
                elif category == 'idle' and not showidle:
                    continue

                self[category] = count

class FuncNode(object):
    def __new__(cls, filedata=None):
        if filedata is None:
            return super(FuncNode, cls).__new__(cls)

        nodes = {}
        for line in filedata['function data']:
            data = line.split(' ')
            node_id = long(data[0], 16)
            node = FuncNode()
            node.symbol = data[1]
            if node.symbol == '':
                node.symbol = 'unknown'
            node.count = long(data[2])
            node.children = [ long(child, 16) for child in data[3:] ]
            nodes[node_id] = node

        for node in nodes.itervalues():
            children = []
            for cid in node.children:
                child = nodes[cid]
                children.append(child)
                child.parent = node
            node.children = tuple(children)
        if not nodes:
            print filedata.filename
            print nodes
        return nodes[0]

    def total(self):
        total = self.count
        for child in self.children:
            total += child.total()

        return total

    def aggregate(self, dict, categorize, incategory):
        category = None
        if categorize:
            category = categorize(self.symbol)

        total = self.count
        for child in self.children:
            total += child.aggregate(dict, categorize, category or incategory)

        if category:
            dict[category] = dict.get(category, 0) + total
            return 0
        elif not incategory:
            dict[self.symbol] = dict.get(self.symbol, 0) + total

        return total

    def dump(self):
        kids = [ child.symbol for child in self.children]
        print '%s %d <%s>' % (self.symbol, self.count, ', '.join(kids))
        for child in self.children:
            child.dump()

    def _dot(self, dot, threshold, categorize, total):
        from pydot import Dot, Edge, Node
        self.dot_node = None

        value = self.total() * 100.0 / total
        if value < threshold:
            return
        if categorize:
            category = categorize(self.symbol)
            if category and category != 'other':
                return
        label = '%s %.2f%%' % (self.symbol, value)
        self.dot_node = Node(self, label=label)
        dot.add_node(self.dot_node)

        for child in self.children:
            child._dot(dot, threshold, categorize, total)
            if child.dot_node is not None:
                dot.add_edge(Edge(self, child))

    def _cleandot(self):
        for child in self.children:
            child._cleandot()
            self.dot_node = None
            del self.__dict__['dot_node']

    def dot(self, dot, threshold=0.1, categorize=None):
        self._dot(dot, threshold, categorize, self.total())
        self._cleandot()

class FuncData(RunData):
    def __init__(self, filename, categorize=None):
        super(FuncData, self).__init__(filename)
        tree = self.tree
        tree.aggregate(self, categorize, incategory=False)
        self.total = tree.total()

    def __getattribute__(self, attr):
        if attr == 'tree':
            return FuncNode(self.filedata)
        return super(FuncData, self).__getattribute__(attr)

    def displayx(self, output=None, maxcount=None):
        if output is None:
            import sys
            output = sys.stdout

        items = [ (val,key) for key,val in self.iteritems() ]
        items.sort(reverse=True)
        for val,key in items:
            if maxcount is not None:
                if maxcount == 0:
                    return
                maxcount -= 1

            percent = val * 100.0 / self.total
            print >>output, '%-30s %8s' % (key, '%3.2f%%' % percent)

class Profile(object):
    # This list controls the order of values in stacked bar data output
    default_categories = [ 'interrupt',
                           'driver',
                           'stack',
                           'buffer',
                           'copy',
                           'syscall',
                           'user',
                           'other',
                           'idle']

    def __init__(self, datatype, categorize=None):
        categories = Profile.default_categories

        self.datatype = datatype
        self.categorize = categorize
        self.data = {}
        self.categories = categories[:]
        self.rcategories = categories[:]
        self.rcategories.reverse()
        self.cpu = 0

    # Read in files
    def inputdir(self, directory):
        import os, os.path, re
        from os.path import expanduser, join as joinpath

        directory = expanduser(directory)
        label_ex = re.compile(r'profile\.(.*).dat')
        for root,dirs,files in os.walk(directory):
            for name in files:
                match = label_ex.match(name)
                if not match:
                    continue

                filename = joinpath(root, name)
                prefix = os.path.commonprefix([root, directory])
                dirname = root[len(prefix)+1:]
                data = self.datatype(filename, self.categorize)
                self.setdata(dirname, match.group(1), data)

    def setdata(self, run, cpu, data):
        if run not in self.data:
            self.data[run] = {}

        if cpu in self.data[run]:
            raise AttributeError, \
                  'data already stored for run %s and cpu %s' % (run, cpu)

        self.data[run][cpu] = data

    def getdata(self, run, cpu):
        try:
            return self.data[run][cpu]
        except KeyError:
            print run, cpu
            return None

    def alldata(self):
        for run,cpus in self.data.iteritems():
            for cpu,data in cpus.iteritems():
                yield run,cpu,data

    def get(self, job, stat, system=None):
        if system is None and hasattr('system', job):
            system = job.system

        if system is None:
            raise AttributeError, 'The job must have a system set'

        cpu = '%s.run%d' % (system, self.cpu)

        data = self.getdata(str(job), cpu)
        if not data:
            return None

        values = []
        for category in self.categories:
            val = float(data.get(category, 0.0))
            if val < 0.0:
                raise ValueError, 'value is %f' % val
            values.append(val)
        total = sum(values)
        return [ v / total * 100.0 for v in values ]

    def dump(self):
        for run,cpu,data in self.alldata():
            print 'run %s, cpu %s' % (run, cpu)
            data.dump()
            print

    def write_dot(self, threshold, jobfile=None, jobs=None):
        import pydot

        if jobs is None:
            jobs = [ job for job in jobfile.jobs() ]

        for job in jobs:
            cpu =  '%s.run%d' % (job.system, self.cpu)
            symbols = self.getdata(job.name, cpu)
            if not symbols:
                continue

            dot = pydot.Dot()
            symbols.tree.dot(dot, threshold=threshold)
            dot.write(symbols.filename[:-3] + 'dot')

    def write_txt(self, jobfile=None, jobs=None, limit=None):
        if jobs is None:
            jobs = [ job for job in jobfile.jobs() ]

        for job in jobs:
            cpu =  '%s.run%d' % (job.system, self.cpu)
            symbols = self.getdata(job.name, cpu)
            if not symbols:
                continue

            output = file(symbols.filename[:-3] + 'txt', 'w')
            symbols.display(output, limit)

    def display(self, jobfile=None, jobs=None, limit=None):
        if jobs is None:
            jobs = [ job for job in jobfile.jobs() ]

        maxsymlen = 0

        thejobs = []
        for job in jobs:
            cpu =  '%s.run%d' % (job.system, self.cpu)
            symbols = self.getdata(job.name, cpu)
            if symbols:
                thejobs.append(job)
                maxsymlen = max(maxsymlen, symbols.maxsymlen)

        for job in thejobs:
            cpu =  '%s.run%d' % (job.system, self.cpu)
            symbols = self.getdata(job.name, cpu)
            print job.name
            symbols.display(limit=limit, maxsymlen=maxsymlen)
            print

from categories import func_categorize, pc_categorize
class PCProfile(Profile):
    def __init__(self, categorize=pc_categorize):
        super(PCProfile, self).__init__(PCData, categorize)

class FuncProfile(Profile):
    def __init__(self, categorize=func_categorize):
        super(FuncProfile, self).__init__(FuncData, categorize)

def usage(exitcode = None):
    print '''\
Usage: %s [-bc] [-g <dir>] [-j <jobfile>] [-n <num>]

    -c           groups symbols into categories
    -b           dumps data for bar charts
    -d           generate dot output
    -g <d>       draw graphs and send output to <d>
    -j <jobfile> specify a different jobfile (default is Test.py)
    -n <n>       selects number of top symbols to print (default 5)
''' % sys.argv[0]

    if exitcode is not None:
        sys.exit(exitcode)

if __name__ == '__main__':
    import getopt, re, sys
    from os.path import expanduser
    from output import StatOutput

    # default option values
    numsyms = 10
    graph = None
    cpus = [ 0 ]
    categorize = False
    showidle = True
    funcdata = True
    jobfilename = 'Test.py'
    dodot = False
    dotfile = None
    textout = False
    threshold = 0.01
    inputfile = None

    try:
        opts, args = getopt.getopt(sys.argv[1:], 'C:cdD:f:g:ij:n:pT:t')
    except getopt.GetoptError:
        usage(2)

    for o,a in opts:
        if o == '-C':
            cpus = [ int(x) for x in a.split(',') ]
        elif o == '-c':
            categorize = True
        elif o == '-D':
            dotfile = a
        elif o == '-d':
            dodot = True
        elif o == '-f':
            inputfile = expanduser(a)
        elif o == '-g':
            graph = a
        elif o == '-i':
            showidle = False
        elif o == '-j':
            jobfilename = a
        elif o == '-n':
            numsyms = int(a)
        elif o == '-p':
            funcdata = False
        elif o == '-T':
            threshold = float(a)
        elif o == '-t':
            textout = True

    if args:
        print "'%s'" % args, len(args)
        usage(1)

    if inputfile:
        catfunc = None
        if categorize:
            catfunc = func_categorize
        data = FuncData(inputfile, categorize=catfunc)

        if dodot:
            import pydot
            dot = pydot.Dot()
            data.tree.dot(dot, threshold=threshold)
            #dot.orientation = 'landscape'
            #dot.ranksep='equally'
            #dot.rank='samerank'
            dot.write(dotfile, format='png')
        else:
            data.display(limit=numsyms)

    else:
        from jobfile import JobFile
        jobfile = JobFile(jobfilename)

        if funcdata:
            profile = FuncProfile()
        else:
            profile = PCProfile()

        if not categorize:
            profile.categorize = None
        profile.inputdir(jobfile.rootdir)

        if graph:
            for cpu in cpus:
                profile.cpu = cpu
                if funcdata:
                    name = 'funcstacks%d' % cpu
                else:
                    name = 'stacks%d' % cpu
                output = StatOutput(jobfile, info=profile)
                output.xlabel = 'System Configuration'
                output.ylabel = '% CPU utilization'
                output.stat = name
                output.graph(name, graph)

        if dodot:
            for cpu in cpus:
                profile.cpu = cpu
                profile.write_dot(jobfile=jobfile, threshold=threshold)

        if textout:
            for cpu in cpus:
                profile.cpu = cpu
                profile.write_txt(jobfile=jobfile)

        if not graph and not textout and not dodot:
            for cpu in cpus:
                if not categorize:
                    profile.categorize = None
                profile.cpu = cpu
                profile.display(jobfile=jobfile, limit=numsyms)


text:
#pragma once
#include <aws/ec2/EC2_EXPORTS.h>
#include <aws/ec2/EC2Request.h>
#include <aws/core/utils/memory/stl/AWSString.h>
#include <aws/ec2/model/AttributeBooleanValue.h>

namespace Aws
{
namespace EC2
{
namespace Model
{

  /*
  */
  class AWS_EC2_API ModifyVolumeAttributeRequest : public EC2Request
  {
  public:
    ModifyVolumeAttributeRequest();
    Aws::String SerializePayload() const override;

    /*

Checks whether you have the required permissions for the action, without actually making the request, and provides an error response. If you have the required permissions, the error response is DryRunOperation. Otherwise, it is UnauthorizedOperation.

    */
    inline bool GetDryRun() const{ return m_dryRun; }

    /*

Checks whether you have the required permissions for the action, without actually making the request, and provides an error response. If you have the required permissions, the error response is DryRunOperation. Otherwise, it is UnauthorizedOperation.

    */
    inline void SetDryRun(bool value) { m_dryRunHasBeenSet = true; m_dryRun = value; }

    /*

Checks whether you have the required permissions for the action, without actually making the request, and provides an error response. If you have the required permissions, the error response is DryRunOperation. Otherwise, it is UnauthorizedOperation.

    */
    inline ModifyVolumeAttributeRequest& WithDryRun(bool value) { SetDryRun(value); return *this;}

    /*

The ID of the volume.

    */
    inline const Aws::String& GetVolumeId() const{ return m_volumeId; }

    /*

The ID of the volume.

    */
    inline void SetVolumeId(const Aws::String& value) { m_volumeIdHasBeenSet = true; m_volumeId = value; }

    /*

The ID of the volume.

    */
    inline void SetVolumeId(Aws::String&& value) { m_volumeIdHasBeenSet = true; m_volumeId = value; }

    /*

The ID of the volume.

    */
    inline void SetVolumeId(const char* value) { m_volumeIdHasBeenSet = true; m_volumeId.assign(value); }

    /*

The ID of the volume.

    */
    inline ModifyVolumeAttributeRequest& WithVolumeId(const Aws::String& value) { SetVolumeId(value); return *this;}

    /*

The ID of the volume.

    */
    inline ModifyVolumeAttributeRequest& WithVolumeId(Aws::String&& value) { SetVolumeId(value); return *this;}

    /*

The ID of the volume.

    */
    inline ModifyVolumeAttributeRequest& WithVolumeId(const char* value) { SetVolumeId(value); return *this;}

    /*

Indicates whether the volume should be auto-enabled for I/O operations.

    */
    inline const AttributeBooleanValue& GetAutoEnableIO() const{ return m_autoEnableIO; }

    /*

Indicates whether the volume should be auto-enabled for I/O operations.

    */
    inline void SetAutoEnableIO(const AttributeBooleanValue& value) { m_autoEnableIOHasBeenSet = true; m_autoEnableIO = value; }

    /*

Indicates whether the volume should be auto-enabled for I/O operations.

    */
    inline void SetAutoEnableIO(AttributeBooleanValue&& value) { m_autoEnableIOHasBeenSet = true; m_autoEnableIO = value; }

    /*

Indicates whether the volume should be auto-enabled for I/O operations.

    */
    inline ModifyVolumeAttributeRequest& WithAutoEnableIO(const AttributeBooleanValue& value) { SetAutoEnableIO(value); return *this;}

    /*

Indicates whether the volume should be auto-enabled for I/O operations.

    */
    inline ModifyVolumeAttributeRequest& WithAutoEnableIO(AttributeBooleanValue&& value) { SetAutoEnableIO(value); return *this;}

  private:
    bool m_dryRun;
    bool m_dryRunHasBeenSet;
    Aws::String m_volumeId;
    bool m_volumeIdHasBeenSet;
    AttributeBooleanValue m_autoEnableIO;
    bool m_autoEnableIOHasBeenSet;
  };

} // namespace Model
} // namespace EC2
} // namespace Aws