text:
import { fun } from "./dynamic-to-circular";

fun();
export const value = 3.14

redpajama_set_name: RedPajamaGithub


text:
#ifndef TENSORFLOW_CORE_FRAMEWORK_MODEL_H_
#define TENSORFLOW_CORE_FRAMEWORK_MODEL_H_

#include <list>
#include <memory>
#include <string>
// TODO(b/114492873): Move this include into core/platform.
#include <thread>  // NOLINT
#include <utility>
#include <vector>

#include "absl/container/flat_hash_map.h"
#include "tensorflow/core/framework/cancellation.h"
#include "tensorflow/core/framework/metrics.h"
#include "tensorflow/core/framework/model.pb.h"
#include "tensorflow/core/framework/types.h"
#include "tensorflow/core/lib/gtl/cleanup.h"
#include "tensorflow/core/lib/gtl/map_util.h"
#include "tensorflow/core/lib/histogram/histogram.h"
#include "tensorflow/core/lib/random/random.h"
#include "tensorflow/core/platform/cpu_info.h"
#include "tensorflow/core/platform/env.h"
#include "tensorflow/core/platform/mutex.h"
#include "tensorflow/core/platform/path.h"

namespace tensorflow {
namespace data {
namespace model {

// A constant that can be used to enable auto-tuning.
constexpr int64 kAutotune = -1;
constexpr char kParallelism[] = "parallelism";
constexpr char kBufferSize[] = "buffer_size";

// A key used to identify the input time of the model.
constexpr char kModelInputTimeKey[] = "model_input_time";

enum class TraversalOrder {
  BFS = 0,
  REVERSE_BFS = 1,
};

// Represents thread-safe state that can be shared between an input pipeline and
// the performance model.
struct SharedState {
 public:
  SharedState(int64 value, std::shared_ptr<mutex> mu,
              std::shared_ptr<condition_variable> cond_var)
      : value(value),
        mu(std::move(mu)),
        cond_var(std::move(cond_var)),
        tunable(value == kAutotune) {}

  double value;
  const std::shared_ptr<mutex> mu;
  const std::shared_ptr<condition_variable> cond_var;
  const bool tunable;
};

// Represents a parameter.
struct Parameter {
  Parameter(const string& name, std::shared_ptr<SharedState> state, double min,
            double max)
      : name(name),
        // Sometimes non-autotune nodes (with `autotune_=false`) may contain
        // parameters (for example inputs of parallel interleave dataset which
        // are not in the current cycle). To avoid unrealistic situation
        // (say `buffer_size=-1` or `parallelism=-1`) in the optimization
        // computation, if the state value is `kAutotune=-1` (just to indicate
        // the `SharedState` is tunable), we initialize the parameter value to
        // be the minimal value of the state.
        value(state->value == kAutotune ? min : state->value),
        min(min),
        max(max),
        state(std::move(state)) {}

  // Human-readable name of the parameter.
  const string name;

  // Identifies the model value of the parameter. This can be different from
  // the actual value (e.g. during optimization search).
  double value;

  // Identifies the minimum value of the parameter.
  const double min;

  // Identifies the maximum value of the parameter.
  const double max;

  // Shared state of the parameter.
  std::shared_ptr<SharedState> state;
};

std::shared_ptr<Parameter> MakeParameter(const string& name,
                                         std::shared_ptr<SharedState> state,
                                         double min, double max);

// Abstract representation of a TensorFlow input pipeline node. It collects
// information about inputs to this node, processing time spent executing the
// node logic, number of elements produced by the node, various other
// information (e.g. batch size or execution parallelism).
//
// Developers of tf.data transformations are not expected to interact with
// this class directly. Boiler plate code for creating the abstract
// representation of the input pipeline and collecting common information has
// been added to the implementation of `DatasetBase` and `DatasetBaseIterator`
// respectively.
//
// In addition, `DatasetBaseIterator` provides wrappers that can be used for
// transformation-specific information collection. The `SetMetadata` wrapper
// can be used to pass arbitrary metadata to the modeling framework, while the
// `StartWork` and `StopWork` wrappers should be used to correctly account for
// processing time of multi-threaded transformation that yield the CPU; such
// transformations should invoke `StartWork()` when a transformation thread
// starts executing (e.g. when created or woken up) and `StopWork()` when a
// transformation thread stops executing (e.g. when returning or waiting).
class Node {
 public:
  // Arguments for `Node` constructor.
  struct Args {
    int64 id;
    string name;
    std::shared_ptr<Node> output;
  };

  using Factory = std::function<std::shared_ptr<Node>(Args)>;
  using NodeVector = std::vector<std::shared_ptr<Node>>;
  using NodePairList =
      std::list<std::pair<std::shared_ptr<Node>, std::shared_ptr<Node>>>;

  explicit Node(Args args)
      : id_(args.id),
        name_(std::move(args.name)),
        autotune_(true),
        buffered_bytes_(0),
        buffered_elements_(0),
        bytes_consumed_(0),
        bytes_produced_(0),
        num_elements_(0),
        processing_time_(0),
        record_metrics_(true),
        metrics_(name_),
        output_(args.output.get()) {}

  virtual ~Node() {
    // Clear the sub-nodes instead of relying on implicit shared pointer
    // destructor to avoid potential stack overflow when the tree is deep.
    std::deque<std::shared_ptr<Node>> queue;
    {
      mutex_lock l(mu_);
      while (inputs_.size() > 0) {
        queue.push_back(inputs_.front());
        inputs_.pop_front();
      }
    }
    while (!queue.empty()) {
      auto node = queue.back();
      queue.pop_back();
      {
        mutex_lock l(node->mu_);
        while (node->inputs_.size() > 0) {
          queue.push_back(node->inputs_.front());
          node->inputs_.pop_front();
        }
      }
    }

    FlushMetrics();
  }

  // Adds an input.
  void add_input(std::shared_ptr<Node> node) TF_LOCKS_EXCLUDED(mu_) {
    mutex_lock l(mu_);
    inputs_.push_back(node);
  }

  // Increments the aggregate processing time by the given delta.
  void add_processing_time(int64 delta) TF_LOCKS_EXCLUDED(mu_) {
    processing_time_ += delta;
  }

  // Returns an indication whether autotuning is enabled for this node.
  bool autotune() const TF_LOCKS_EXCLUDED(mu_) {
    return autotune_;
  }

  // Returns the number of bytes stored in this node's buffer.
  int64 buffered_bytes() const TF_LOCKS_EXCLUDED(mu_) {
    return buffered_bytes_;
  }

  // Returns the number of elements stored in this node's buffer.
  int64 buffered_elements() const TF_LOCKS_EXCLUDED(mu_) {
    return buffered_elements_;
  }

  // Returns the number of bytes consumed by the node.
  int64 bytes_consumed() const TF_LOCKS_EXCLUDED(mu_) {
    return bytes_consumed_;
  }

  // Returns the number of bytes produced by the node.
  int64 bytes_produced() const TF_LOCKS_EXCLUDED(mu_) {
    return bytes_produced_;
  }

  // Indicates whether the node has tunable parameters.
  bool has_tunable_parameters() const TF_LOCKS_EXCLUDED(mu_) {
    tf_shared_lock l(mu_);
    for (const auto& pair : parameters_) {
      if (pair.second->state->tunable) return true;
    }
    return false;
  }

  // Returns the unique node ID.
  int64 id() const TF_LOCKS_EXCLUDED(mu_) { return id_; }

  // Returns the node inputs.
  std::list<std::shared_ptr<Node>> inputs() const TF_LOCKS_EXCLUDED(mu_) {
    tf_shared_lock l(mu_);
    return inputs_;
  }

  // Returns a longer node name that is guaranteed to be unique.
  string long_name() const { return strings::StrCat(name_, "(id:", id_, ")"); }

  // Returns the node name.
  const string& name() const { return name_; }

  // Returns the number of elements produced by the node.
  int64 num_elements() const TF_LOCKS_EXCLUDED(mu_) {
    return num_elements_;
  }

  // Returns the node output.
  Node* output() const { return output_; }

  // Returns the parameter value.
  double parameter_value(const string& name) const TF_LOCKS_EXCLUDED(mu_) {
    tf_shared_lock l(mu_);
    return parameters_.at(name)->state->value;
  }

  // Returns the aggregate processing time.
  int64 processing_time() const TF_LOCKS_EXCLUDED(mu_) {
    return processing_time_;
  }

  // Records that the node consumed the given number of bytes.
  void record_bytes_consumed(int64 num_bytes) { bytes_consumed_ += num_bytes; }

  // Records that the node produced the given number of bytes.
  void record_bytes_produced(int64 num_bytes) { bytes_produced_ += num_bytes; }

  // Records the change in this node's buffer.
  void record_buffer_event(int64 bytes_delta, int64 elements_delta) {
    buffered_bytes_ += bytes_delta;
    buffered_elements_ += elements_delta;
  }

  // Records that the node produced an element.
  void record_element() TF_LOCKS_EXCLUDED(mu_) {
    num_elements_++;
  }

  // Records that a node thread has started executing.
  void record_start(int64 time_nanos) TF_LOCKS_EXCLUDED(mu_) {
    DCHECK_EQ(work_start_, 0);
    work_start_ = time_nanos;
  }

  // Records that a node thread has stopped executing.
  void record_stop(int64 time_nanos) TF_LOCKS_EXCLUDED(mu_) {
    // TODO(jsimsa): Use DCHECK_NE(work_start_, 0) here.
    if (work_start_ != 0) {
      processing_time_ += time_nanos - work_start_;
      work_start_ = 0;
    } else {
      VLOG(1) << "Encountered a stop event without a matching start event.";
    }
  }

  // Returns whether work is currently being recorded, i.e. whether we are
  // currently between a `record_start` and a `record_stop`.
  bool is_recording() TF_LOCKS_EXCLUDED(mu_) { return work_start_ > 0; }

  // Removes an input.
  void remove_input(std::shared_ptr<Node> input) TF_LOCKS_EXCLUDED(mu_) {
    mutex_lock l(mu_);
    inputs_.remove(input);
  }

  // Sets the value that determines whether autotuning is enabled for this node.
  void set_autotune(bool autotune) TF_LOCKS_EXCLUDED(mu_) {
    autotune_.store(autotune);
  }

  // Given the average time between events when the elements in the buffer are
  // produced (`producer_time`), the average time between events when elements
  // in the buffer are consumed (`consumer_time`) and the buffer size, the
  // method computes the expected time an consumer event will have to wait.
  //
  // The wait time is approximated as the product of the probability the buffer
  // will be empty and the time it takes to produce an element into the buffer.
  //
  // The formula used for computing the probability is derived by modeling the
  // problem as an M/M/1/K queue
  // (https://en.wikipedia.org/wiki/Birth%E2%80%93death_process#M/M/1/K_queue).
  //
  // Collects derivatives of `ComputeWaitTime` w.r.t `producer_time`,
  // `consumer_time' and `buffer_size` if the corresponding pointers are not
  // `nullptr`.
  static double ComputeWaitTime(const double& producer_time,
                                const double& consumer_time,
                                const double& buffer_size,
                                double* producer_time_derivative,
                                double* consumer_time_derivative,
                                double* buffer_size_derivative);

  // Collects tunable parameters in the subtree rooted in this node.
  void CollectTunableParameters(
      absl::flat_hash_map<string, std::shared_ptr<Parameter>>* parameters) const
      TF_LOCKS_EXCLUDED(mu_);

  // Returns a human-readable representation of this node.
  string DebugString() const TF_LOCKS_EXCLUDED(mu_);

  // Flushes the metrics recorded by this node.
  void FlushMetrics() TF_LOCKS_EXCLUDED(mu_);

  // Returns the per-element output time for this node and if `gradients` is not
  // `nullptr`, collects the output time gradient w.r.t. tunable parameters of
  // the subtree rooted in this node.
  double OutputTime(absl::flat_hash_map<string, double>* input_times,
                    absl::flat_hash_map<string, double>* gradients) const
      TF_LOCKS_EXCLUDED(mu_);

  // Returns a copy of this node, making a deep copy of its inputs and a
  // shallow copy of its tunable parameters.
  //
  // The purpose for this method is to allow the model optimization logic to
  // operate over immutable state while allowing concurrent model updates.
  std::shared_ptr<Node> Snapshot() const TF_LOCKS_EXCLUDED(mu_);

  // Returns the per-element processing time spent in this node.
  double SelfProcessingTime() const TF_LOCKS_EXCLUDED(mu_);

  // Returns the total number of bytes buffered in all nodes in the subtree for
  // which autotuning is enabled.
  double TotalBufferedBytes() const TF_LOCKS_EXCLUDED(mu_);

  // Collects the total buffer limit of all nodes in the subtree for which
  // autotuning is enabled. This number represents the amount of memory that
  // would be used by the subtree nodes if all of their buffers were full.
  double TotalMaximumBufferedBytes() const TF_LOCKS_EXCLUDED(mu_);

  // Returns the per-element CPU time spent in the subtree rooted in this node.
  // If `processing_times` is not `nullptr`, collects the per-element CPU time
  // spent in each node of the subtree.
  double TotalProcessingTime(
      absl::flat_hash_map<string, double>* processing_times)
      TF_LOCKS_EXCLUDED(mu_);

  // Recursively produces a proto for this node and its subtree.
  virtual Status ToProto(ModelProto::Node* node_proto) const;

  // Recursively restores a node and its subtree from the proto.
  static Status FromProto(ModelProto::Node node_proto,
                          std::shared_ptr<Node> output,
                          std::shared_ptr<Node>* node);

 protected:
  // Used for (incrementally) recording metrics. The class is thread-safe.
  class Metrics {
   public:
    explicit Metrics(const string& name)
        : bytes_consumed_counter_(metrics::GetTFDataBytesConsumedCounter(name)),
          bytes_produced_counter_(metrics::GetTFDataBytesProducedCounter(name)),
          num_elements_counter_(metrics::GetTFDataElementsCounter(name)),
          recorded_bytes_consumed_(0),
          recorded_bytes_produced_(0),
          recorded_num_elements_(0) {}

    // Expects the total number of bytes consumed and records the delta since
    // last invocation.
    void record_bytes_consumed(int64 total_bytes) {
      int64 delta =
          total_bytes - recorded_bytes_consumed_.exchange(total_bytes);
      bytes_consumed_counter_->IncrementBy(delta);
    }

    // Expects the total number of bytes produced and records the delta since
    // last invocation.
    void record_bytes_produced(int64 total_bytes) {
      int64 delta =
          total_bytes - recorded_bytes_produced_.exchange(total_bytes);
      bytes_produced_counter_->IncrementBy(delta);
    }

    // Expects the total number of elements produced and records the delta since
    // last invocation.
    void record_num_elements(int64 total_elements) {
      int64 delta =
          total_elements - recorded_num_elements_.exchange(total_elements);
      num_elements_counter_->IncrementBy(delta);
    }

   private:
    monitoring::CounterCell* const bytes_consumed_counter_;
    monitoring::CounterCell* const bytes_produced_counter_;
    monitoring::CounterCell* const num_elements_counter_;
    std::atomic<int64> recorded_bytes_consumed_;
    std::atomic<int64> recorded_bytes_produced_;
    std::atomic<int64> recorded_num_elements_;
  };

  // Returns the number of inputs.
  int64 num_inputs() const TF_SHARED_LOCKS_REQUIRED(mu_) {
    int64 num_inputs = 0;
    for (auto& input : inputs_) {
      // Inputs for which autotuning is disabled are excluded.
      if (input->autotune()) {
        ++num_inputs;
      }
    }
    return num_inputs;
  }

  // Creates a clone of this node.
  virtual std::shared_ptr<Node> Clone(std::shared_ptr<Node> output) const
      TF_SHARED_LOCKS_REQUIRED(mu_) = 0;

  // Returns the average size of an element buffered in this node.
  double AverageBufferedElementSize() const TF_SHARED_LOCKS_REQUIRED(mu_);

  // Returns the sum of per-element output time for the tunable inputs of this
  // node.
  double OutputTimeForInputs(
      const absl::flat_hash_map<string, double>& output_times) const
      TF_SHARED_LOCKS_REQUIRED(mu_);

  // Returns the sum of output time gradient w.r.t. input time for the tunable
  // inputs of this node.
  double OutputTimeGradientsForInputs(
      const absl::flat_hash_map<string, double>& output_time_gradients) const
      TF_SHARED_LOCKS_REQUIRED(mu_);

  // Computes the input time for this node and stores it in `input_times`.
  virtual void InputTimeLocked(absl::flat_hash_map<string, double>* input_times)
      const TF_SHARED_LOCKS_REQUIRED(mu_) = 0;

  // Computes the per-element output time for this node and stores it in
  // `output_times`. If `gradients` is not `nullptr`, computes the output time
  // gradient w.r.t. tunable parameters of the subtree rooted in this node and
  // stores it in `gradients`, also computes the output time gradient w.r.t.
  // input time and stores it in `output_time_gradients`.
  virtual void OutputTimeLocked(
      const absl::flat_hash_map<string, double>& input_times,
      absl::flat_hash_map<string, double>* gradients,
      absl::flat_hash_map<string, double>* output_times,
      absl::flat_hash_map<string, double>* output_time_gradients) const
      TF_SHARED_LOCKS_REQUIRED(mu_) = 0;

  // Returns the sum of per-element processing time for the inputs of this node
  // by adding values for input nodes in `total_processing_times`. Processing
  // time for a given input is a weighted combination of a statistic based on
  // history of input processing time and the actual time. This is done to
  // improve accuracy of processing time estimation for newly created inputs.
  //
  // Uniform distribution of per-element processing times across different
  // inputs is assumed.
  double TotalProcessingTimeForInputs(
      const absl::flat_hash_map<string, double>& total_processing_times)
      TF_SHARED_LOCKS_REQUIRED(mu_);

  // Returns the per-element processing time spent in this node.
  double SelfProcessingTimeLocked() const TF_SHARED_LOCKS_REQUIRED(mu_);

  // Computes the per-element CPU time spent in the subtree rooted in this node
  // and stores it in `total_processing_times`. If `processing_times` is not
  // `nullptr`, collects the per-element CPU time spent in each node of the
  // subtree.
  virtual void TotalProcessingTimeLocked(
      absl::flat_hash_map<string, double>* processing_times,
      absl::flat_hash_map<string, double>* total_processing_times)
      TF_SHARED_LOCKS_REQUIRED(mu_) = 0;

  // Returns a vector of nodes of the subtree rooted in this node. The nodes are
  // either in breadth-first search or reverse breadth-first search order
  // depending on the `order` argument. The nodes are collected based on the
  // results of the `collect_node` predicate: if the predicate returns `false`
  // for a given node, then the subtree rooted in this node is excluded. The
  // root node itself is not collected.
  NodeVector CollectNodes(TraversalOrder order,
                          bool collect_node(const std::shared_ptr<Node>)) const
      TF_SHARED_LOCKS_REQUIRED(mu_);

  // Collect tunable parameters on the nodes which have recorded elements.
  void CollectTunableParametersHelper(
      absl::flat_hash_map<string, std::shared_ptr<Parameter>>* parameters) const
      TF_SHARED_LOCKS_REQUIRED(mu_);

  // Build up debug string for the node and store in the debug strings map.
  void DebugStringHelper(absl::flat_hash_map<string, string>* debug_strings)
      const TF_SHARED_LOCKS_REQUIRED(mu_);

  // Copy the node and add the (input, copy) pairs to the NodePairList.
  std::shared_ptr<Node> SnapshotHelper(std::shared_ptr<Node> cloned_output,
                                       NodePairList* node_pairs) const;

  // Compute total buffered bytes for the node and store in the total bytes map.
  void TotalBufferedBytesHelper(
      absl::flat_hash_map<string, double>* total_bytes) const
      TF_SHARED_LOCKS_REQUIRED(mu_);

  // Compute total maximum buffered bytes for the node and store in the total
  // bytes map.
  void TotalMaximumBufferedBytesHelper(
      absl::flat_hash_map<string, double>* total_bytes) const
      TF_SHARED_LOCKS_REQUIRED(mu_);

  // Compute and return the maximum buffered bytes on the node itself. By
  // default non-tunable nodes are assumed not to buffer any bytes, so the
  // tunable nodes as subclasses are expected to override this method to ensure
  // that the optimization algorithm respects the memory budget.
  virtual double MaximumBufferedBytes() const TF_SHARED_LOCKS_REQUIRED(mu_);

  // Restores node from the proto. Note that this is not done recursively, i.e.
  // input nodes are not restored.
  static Status FromProtoHelper(ModelProto::Node node_proto,
                                std::shared_ptr<Node> node);

  // Stores the time passed to the last call to `Node::record_start()` on the
  // current thread.
  //
  // NOTE: This thread-local variable is shared between all instances of `Node`
  // on which the same thread calls `record_start()` or `record_stop()`. It
  // relies on the invariant that at most one `Node` can be "active" on a
  // particular thread at any time. Therefore if `n->record_start()` is called
  // on thread `t`, then `n->record_stop()` must be called before another call
  // to `Node::record_start()` (for any node).
  static thread_local int64 work_start_;  // Will be initialized to zero.

  mutable mutex mu_;
  const int64 id_;
  const string name_;

  // Indicates whether the subtree rooted in this node should be included in
  // autotuning. In particular, if this is `false`, then the subtree is excluded
  // from computation of output time and processing time.
  std::atomic<bool> autotune_;
  std::atomic<int64> buffered_bytes_;
  std::atomic<int64> buffered_elements_;
  std::atomic<int64> bytes_consumed_;
  std::atomic<int64> bytes_produced_;
  std::atomic<int64> num_elements_;
  std::atomic<int64> processing_time_;
  std::atomic<bool> record_metrics_;
  Metrics metrics_;
  absl::flat_hash_map<string, std::shared_ptr<Parameter>> parameters_
      TF_GUARDED_BY(mu_);

  // Statistic of inputs processing time history.
  double input_processing_time_sum_ = 0.0L;
  int64 input_processing_time_count_ = 0;

  // Inputs of this node. These can represent an iterator created from the input
  // dataset but also other input iterators (e.g. created by the user-defined
  // functions of `flat_map` or `interleave`).
  std::list<std::shared_ptr<Node>> inputs_ TF_GUARDED_BY(mu_);

  // The reference to the output node is not owned so that deletion of a
  // node results in recursive deletion of the subtree rooted in the node.
  Node* const output_;
};

// InterleaveMany is used to model datasets whose inputs are used to create
// datasets whose elements are then interleaved.
std::shared_ptr<Node> MakeInterleaveManyNode(Node::Args args);

// AsyncInterleaveMany nodes are the asynchronous version of InterleaveMany
// nodes.
std::shared_ptr<Node> MakeAsyncInterleaveManyNode(
    Node::Args args, std::vector<std::shared_ptr<Parameter>> parameters);

// KnownMany nodes model datasets that synchronously consume known number of
// input element per output element.
std::shared_ptr<Node> MakeKnownRatioNode(Node::Args args, double ratio);

// AsyncKnownRatio nodes are the asynchronous version of KnownRate nodes.
std::shared_ptr<Node> MakeAsyncKnownRatioNode(
    Node::Args args, double ratio, double memory_ratio,
    std::vector<std::shared_ptr<Parameter>> parameters);

std::shared_ptr<Node> MakeAsyncKnownRatioNode(
    Node::Args args, double ratio,
    std::vector<std::shared_ptr<Parameter>> parameters);

// Source nodes represent data sources.
std::shared_ptr<Node> MakeSourceNode(Node::Args args);

// UnknownMany nodes represent datasets that synchronously consume an
// unknown number of input elements per output.
//
// Unlike KnownRatio nodes which expect the ratio between inputs and outputs is
// specified as a parameter, UnknownRatio estimates the ratio empirically.
std::shared_ptr<Node> MakeUnknownRatioNode(Node::Args args);

// Unknown nodes represent datasets for which we do not have a model. It acts
// as pass-through between inputs and output.
std::shared_ptr<Node> MakeUnknownNode(Node::Args args);

// Abstract representation of a TensorFlow input pipeline that can be used
// for collecting runtime information and optimizing performance. It collects
// runtime information about execution of the input pipeline that is used to
// create a performance model, which is in turn used to identify optimal values
// of tunable parameters.
//
// Developers of tf.data transformations are not expected to interact with this
// class directly. Boiler plate code for creating the abstract representation of
// the input pipeline and collecting runtime information has been added to the
// implementation of `DatasetBase` and `DatasetBaseIterator` respectively.
class Model {
 public:
  using OptimizationParams = ModelProto::OptimizationParams;

  // Creates a new model.
  Model()
      : collect_resource_usage_(false),
        optimization_period_ms_(kOptimizationPeriodMinMs) {
    const char* save_dir = std::getenv("TF_DATA_AUTOTUNE_DEBUG_DIR");
    if (save_dir) {
      save_dir_ = string(save_dir);
    }
  }

  ~Model() {
    if (!save_dir_.empty()) {
      save_thread_cancelled_ = true;
      save_cond_var_.notify_all();
    }
  }

  // Indicates whether to collect resource usage.
  bool collect_resource_usage() const { return collect_resource_usage_; }

  // Returns a pointer to the model's output node.
  const std::shared_ptr<Node> output() {
    mutex_lock l(mu_);
    return output_;
  }

  // Adds a node with the given name and given parent.
  void AddNode(Node::Factory factory, const string& name,
               std::shared_ptr<Node> parent, std::shared_ptr<Node>* out_node)
      TF_LOCKS_EXCLUDED(mu_);

  // Uses the given algorithm and resource budgets to periodically perform the
  // autotuning optimization.
  //
  // To terminate the execution of the optimization loop, the caller needs to
  // invoke `cancellation_mgr->StartCancel()`.
  Status OptimizeLoop(AutotuneAlgorithm algorithm, int64 cpu_budget,
                      int64 ram_budget,
                      CancellationManager* cancellation_manager);

  // Uses the given algorithm and resource budgets to perform the autotuning
  // optimization.
  void Optimize(AutotuneAlgorithm algorithm, int64 cpu_budget, int64 ram_budget,
                double model_input_time,
                CancellationManager* cancellation_manager);

  // Removes the given node.
  void RemoveNode(std::shared_ptr<Node> node) TF_LOCKS_EXCLUDED(mu_);

  // Produces a proto for this model.
  Status ToProto(ModelProto* model_proto);

  // Restores a model from the proto.
  static Status FromProto(ModelProto model_proto,
                          std::unique_ptr<Model>* model);

  // Saves this model with a given snapshot and its optimization parameters to a
  // file. Note that the file directory must already exist.
  Status Save(const string& fname, std::shared_ptr<Node> snapshot,
              const OptimizationParams& optimization_params);

  // Loads a model and its optimization parameters from a file with the given
  // name.
  static Status Load(const string& fname, std::unique_ptr<Model>* model,
                     OptimizationParams* optimization_params);

 private:
  static constexpr int64 kOptimizationPeriodMinMs = 10;
  static constexpr int64 kOptimizationPeriodMaxMs =
      60 * EnvTime::kSecondsToMillis;

  // Maximum number of optimization snapshots kept in a buffer for saving.
  static constexpr int64 kMaxNumBufferedOptimizeArgs = 100;

  // Collects tunable parameters in the tree rooted in the given node, returning
  // a mapping from a (unique) node name to a tunable parameter.
  absl::flat_hash_map<string, std::shared_ptr<Parameter>>
  CollectTunableParameters(std::shared_ptr<Node> node);

  // Flushes metrics recorded by the model.
  void FlushMetrics() TF_LOCKS_EXCLUDED(mu_);

  // This optimization algorithm starts by setting all tunable parallelism
  // parameters to the minimum value. It then repeatedly identifies the
  // parameter whose increase in parallelism decreases the output time the most.
  // This process is repeated until all parameters reach their maximum values or
  // the projected output time is less than or equal to the processing time
  // needed to produce an element divided by CPU budget.
  void OptimizeHillClimb(std::shared_ptr<Node> snapshot,
                         const OptimizationParams& optimization_params,
                         CancellationManager* cancellation_manager);

  // This optimization algorithm starts by setting all tunable parallelism
  // parameters to the minimum value. It then improves current parameters by
  // making a step in the direction opposite to the gradient of `OutputTime` and
  // projecting resulting values on the feasible intervals. Improvement step is
  // repeated until either the output time improvement is smaller than threshold
  // value or the output time is less than the processing time needed to produce
  // an element divided by CPU budget.
  void OptimizeGradientDescent(std::shared_ptr<Node> snapshot,
                               const OptimizationParams& optimization_params,
                               CancellationManager* cancellation_manager);

  // Collects the output time and if `gradients` is not `nullptr`, the output
  // time gradient w.r.t. tunable parameters of the subtree rooted in the given
  // node.
  double OutputTime(std::shared_ptr<Node> node, double model_input_time,
                    absl::flat_hash_map<string, double>* gradients);

  // Determines if we should stop the gradient descent optimization iterations
  // based on number of increasable parameters, CPU budget, RAM budget and
  // current resource usage.
  bool ShouldStop(
      int64 cpu_budget, int64 ram_budget,
      const absl::flat_hash_map<string, std::shared_ptr<Parameter>>& parameters,
      const absl::flat_hash_map<string, std::shared_ptr<Parameter>>&
          parallelism_parameters,
      const absl::flat_hash_map<string, std::shared_ptr<Parameter>>&
          buffer_size_parameters,
      std::shared_ptr<Node> snapshot, bool* cpu_budget_reached);

  // Collects the processing time for the given node.
  double TotalProcessingTime(std::shared_ptr<Node> node);

  // Collects the total number of bytes buffered in all nodes in the subtree
  // rooted in the given node for which autotuning is enabled.
  double TotalBufferedBytes(std::shared_ptr<Node> node);

  // Collects the total buffer limit of all nodes in the subtree rooted in the
  // given node for which autotuning is enabled. This number represents the
  // amount of memory that would be used by the subtree nodes if all of their
  // buffers were full.
  double TotalMaximumBufferedBytes(std::shared_ptr<Node> node);

  // Starts a model saving thread if it hasn't started yet.
  Status EnsureSaveLoopThreadStarted();

  // Periodically saves the state of optimization that is kept in
  // `save_buffer_`.
  //
  // The saving loop is terminated when the model is destroyed.
  Status SaveLoop();

  // Used for coordination between different input pipeline threads. Exclusive
  // access is required only when adding or removing nodes. Concurrent access to
  // existing nodes is protected by a node mutex.
  mutex mu_;
  // Used for coordinating the optimization loop and model modifications.
  condition_variable optimize_cond_var_;
  int64 id_counter_ TF_GUARDED_BY(mu_) = 1;
  std::shared_ptr<Node> output_ TF_GUARDED_BY(mu_);

  // Indicates whether the modeling framework should collect resource usage
  // (e.g. CPU, memory). The logic for collecting this information assumes that
  // the collection is not repeatedly disabled and enabled. As a consequence,
  // the implementation starts collecting resource usage when it encounters a
  // tunable parameter (because the information is used for tuning the value of
  // the parameter) and never stops.
  std::atomic<bool> collect_resource_usage_;

  // Determines the time the optimization loop should wait between
  // running optimizations.
  int64 optimization_period_ms_ TF_GUARDED_BY(mu_);

  // Thread that runs the model saving loop.
  std::unique_ptr<Thread> save_thread_ TF_GUARDED_BY(mu_);

  // Used for coordinating the saving loop and model optimization.
  condition_variable save_cond_var_;

  // Indicates whether the save thread is cancelled.
  bool save_thread_cancelled_ = false;

  // Contains path to the model saving directory if saving is enabled, empty
  // otherwise.
  string save_dir_;

  // Contains pairs of model snapshots and optimization parameters to be saved
  // if model saving is enabled, empty otherwise. Buffer elements are pushed by
  // `OptimizeLoop` and popped by `SaveLoop`.
  std::deque<std::pair<std::shared_ptr<Node>, OptimizationParams>> save_buffer_
      TF_GUARDED_BY(mu_);
};

}  // namespace model
}  // namespace data
}  // namespace tensorflow

#endif  // TENSORFLOW_CORE_FRAMEWORK_MODEL_H_


text:
using System;
using System.Collections.Generic;
using Content.Server.Botany;
using Content.Server.GameObjects.Components.Botany;
using Content.Shared.GameTicking;
using JetBrains.Annotations;
using Robust.Shared.GameObjects.Systems;
using Robust.Shared.Interfaces.GameObjects;
using Robust.Shared.Interfaces.Timing;
using Robust.Shared.IoC;
using Robust.Shared.Prototypes;

namespace Content.Server.GameObjects.EntitySystems
{
    [UsedImplicitly]
    public class PlantSystem : EntitySystem, IResettingEntitySystem
    {
        [Dependency] private readonly IComponentManager _componentManager = default!;
        [Dependency] private readonly IPrototypeManager _prototypeManager = default!;

        private int _nextUid = 0;
        private readonly Dictionary<int, Seed> _seeds = new Dictionary<int,Seed>();

        private float _timer = 0f;

        public IReadOnlyDictionary<int, Seed> Seeds => _seeds;

        public override void Initialize()
        {
            base.Initialize();

            PopulateDatabase();
        }

        private void PopulateDatabase()
        {
            _nextUid = 0;

            _seeds.Clear();

            foreach (var seed in _prototypeManager.EnumeratePrototypes<Seed>())
            {
                AddSeedToDatabase(seed);
            }
        }

        public bool AddSeedToDatabase(Seed seed)
        {
            // If it's not -1, it's already in the database. Probably.
            if (seed.Uid != -1)
                return false;

            seed.Uid = GetNextSeedUid();
            _seeds[seed.Uid] = seed;
            return true;
        }

        private int GetNextSeedUid()
        {
            return _nextUid++;
        }

        public override void Update(float frameTime)
        {
            base.Update(frameTime);

            _timer += frameTime;
            if (_timer < 3f)
                return;

            _timer = 0f;

            foreach (var plantHolder in _componentManager.EntityQuery<PlantHolderComponent>())
            {
                plantHolder.Update();
            }
        }

        public void Reset()
        {
            PopulateDatabase();
        }
    }
}


text:
/* */
var global    = require('./$.global')
  , core      = require('./$.core')
  , PROTOTYPE = 'prototype';
var ctx = function(fn, that){
  return function(){
    return fn.apply(that, arguments);
  };
};
var $def = function(type, name, source){
  var key, own, out, exp
    , isGlobal = type & $def.G
    , isProto  = type & $def.P
    , target   = isGlobal ? global : type & $def.S
        ? global[name] : (global[name] || {})[PROTOTYPE]
    , exports  = isGlobal ? core : core[name] || (core[name] = {});
  if(isGlobal)source = name;
  for(key in source){
    // contains in native
    own = !(type & $def.F) && target && key in target;
    if(own && key in exports)continue;
    // export native or passed
    out = own ? target[key] : source[key];
    // prevent global pollution for namespaces
    if(isGlobal && typeof target[key] != 'function')exp = source[key];
    // bind timers to global for call from export context
    else if(type & $def.B && own)exp = ctx(out, global);
    // wrap global constructors for prevent change them in library
    else if(type & $def.W && target[key] == out)!function(C){
      exp = function(param){
        return this instanceof C ? new C(param) : C(param);
      };
      exp[PROTOTYPE] = C[PROTOTYPE];
    }(out);
    else exp = isProto && typeof out == 'function' ? ctx(Function.call, out) : out;
    // export
    exports[key] = exp;
    if(isProto)(exports[PROTOTYPE] || (exports[PROTOTYPE] = {}))[key] = out;
  }
};
// type bitmap
$def.F = 1;  // forced
$def.G = 2;  // global
$def.S = 4;  // static
$def.P = 8;  // proto
$def.B = 16; // bind
$def.W = 32; // wrap
module.exports = $def;


text:
using System.Reflection;
using System.Runtime.InteropServices;

[assembly: AssemblyTitle("Windows Azure Table Storage ADO.NET Data Provider")]
[assembly: AssemblyDescription(".NET Framework data provider intended to allow developers to write ADO.NET code against Windows Azure Table Storage.")]
[assembly: ComVisible(false)]


text:
package och.front.service;

import static och.api.model.PropKey.*;
import static och.api.model.user.SecurityContext.*;
import static och.api.model.user.UserRole.*;
import static och.service.props.PropsOps.*;
import static och.util.ExceptionUtil.*;
import static och.util.StringUtil.*;
import static och.util.Util.*;
import static och.util.sql.SingleTx.*;

import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

import javax.servlet.ServletContext;
import javax.sql.DataSource;

import och.api.model.PropKey;
import och.api.model.tariff.Tariff;
import och.api.model.user.User;
import och.api.model.user.UserRole;
import och.comp.cache.client.CacheClient;
import och.comp.captcha.Captcha;
import och.comp.db.base.BaseDb;
import och.comp.db.main.MainDb;
import och.comp.mail.MailService;
import och.comp.paypal.PaypalClient;
import och.comp.paypal.PaypalClientStub;
import och.comp.paypal.PaypalSoapClient;
import och.comp.template.Templates;
import och.comp.tocheckout.ToCheckoutProvider;
import och.front.service.event.DBInitedEvent;
import och.service.AsyncService;
import och.service.BaseApp;
import och.service.EventService;
import och.service.props.Props;
import och.util.Util;
import och.util.geoip.GeoIp;

import org.apache.commons.logging.Log;

public class FrontApp extends BaseApp {

	public final static String DEFAULT_INIT_CHAT_ACC_1 = "demo";
	public final static String DEFAULT_INIT_CHAT_ACC_2 = "demo2";

	private Log log = getLog(getClass());

	FrontAppContext c;

	public final String id;

	public final SecurityService security;
	public final ChatService chats;
	public final UserService users;
	public final Captcha captcha;
	public final BillingService billing;

	public final AdminService admin;

	public FrontApp(FrontAppContext context) throws Exception {
		super(context);
		this.c = context;
		c.root = this;
		this.id = c.props.getVal(frontApp_id, Util.randomSimpleId());

		ArrayList<BaseFrontService> services = new ArrayList<>();

		captcha = c.captcha;
		admin = addToList(services, new AdminService(c));
		security = addToList(services, new SecurityService(c));
		chats = addToList(services, new ChatService(c));
		users = addToList(services, new UserService(c));
		billing = addToList(services, new BillingService(c));

		//final init
		for (BaseFrontService s : services) s.init();

		initDB();

		c.events.fireEvent(new DBInitedEvent());
	}

	private <T extends BaseFrontService> T addToList(List<BaseFrontService> services, T s){
		services.add(s);
		return s;
	}

	private void initDB() throws Exception {

		if( ! c.db.isNewTables()){
			return;
		}

		pushToSecurityContext_SYSTEM_USER();
		setSingleTxMode();
		try {

			//servers
			String serversInitVal = props.getStrVal(chats_server_init_urls);
			List<String> serversData = strToList(serversInitVal, ",");
			for (String data : serversData) {
				List<String> dataList = strToList(data," ");
				if(dataList.size() < 2){
					log.error("invalid server data: "+data);
					continue;
				}
				String httpUrl = dataList.get(0);
				String httpsUrl = dataList.get(1);
				chats.createServer(httpUrl, httpsUrl);
			}

			//admins
			List<Long> adminsIds = initUsers(users_init_adminLogins, users_init_adminPsws, ADMIN);
			initUsers(users_init_moderLogins, users_init_moderPsws, MODERATOR);

			//tariffs
			{
				//pause tariff
				chats.createTariff(props.getBigDecimalVal(tariff_pausePrice), false, 0, Tariff.PAUSE_TARIFF_ID);

				//other tariffs
				BigDecimal curTariffPrice = new BigDecimal(props.getLongVal(tariffs_init_val));
				int delta = props.getIntVal(tariffs_init_delta);
				int count = props.getIntVal(tariffs_init_count);
				String publicTariffsVal = props.getStrVal(tariffs_init_publicIds);
				Set<Long> publicTariffs = new HashSet<>(convert(strToList(publicTariffsVal), (s)-> tryParseLong(s, 0L)));

				HashMap<Long, Integer> maxOperatorsById = new HashMap<Long, Integer>();
				List<String> maxOps = strToList(props.getStrVal(tariffs_maxOperators));
				for(String pair : maxOps){
					List<String> idCount = strToList(pair, "-");
					if(isEmpty(idCount) || idCount.size() < 2) continue;
					maxOperatorsById.put(tryParseLong(idCount.get(0), -1L), tryParseInt(idCount.get(1), 0));
				}

				for(int i=0; i < count; i++){

					long expectedId = i+1;
					boolean isPublic = publicTariffs.contains(expectedId);
					Integer maxOperators = maxOperatorsById.get(expectedId);
					if(maxOperators == null) maxOperators = 0;
					chats.createTariff(curTariffPrice, isPublic, maxOperators);

					curTariffPrice = curTariffPrice.add(new BigDecimal(delta));
				}
			}

			ArrayList<String> chatsUids = new ArrayList<>();

			if( ! isEmpty(adminsIds)){

				Long chatOwnerId = adminsIds.get(0);

				//chats
				String chatsInitVal = props.getVal(chats_init_accounts, "1 "+DEFAULT_INIT_CHAT_ACC_1+",1 "+DEFAULT_INIT_CHAT_ACC_2);
				long tariffId = props.getLongVal(chats_init_tariff);
				List<String> chatsData = strToList(chatsInitVal, ",");
				for (String data : chatsData) {
					List<String> dataList = strToList(data," ");
					if(dataList.size() < 2){
						log.error("invalid chat data: "+data);
						continue;
					}
					long serverId = tryParseLong(dataList.get(0), 0L);
					if(serverId == 0L){
						log.error("invalid serverId for chat: "+data);
						continue;
					}

					String uid = dataList.get(1);
					String chatName = null;
					boolean adminNotify = false;
					chats.createAcc(serverId, uid, chatOwnerId, chatName, tariffId, adminNotify);
					chatsUids.add(uid);
				}
			}

			//owner operators for chats
			if( ! isEmpty(chatsUids) && ! isEmpty(adminsIds)){
				for (String uid : chatsUids) {
					for (Long userId : adminsIds) {
						chats.setOperatorForAcc(uid, userId);
					}
				}
			}

		}catch (Throwable t) {
			rollbackSingleTx();
			throw getExceptionOrThrowError(t);
		}
		finally {
			popUserFromSecurityContext();
			closeSingleTx();
		}
	}

	private List<Long> initUsers(PropKey usersProp, PropKey pswsProp, UserRole... roles) throws Exception {
		List<String> logins = strToList(props.getStrVal(usersProp));
		List<String> psws = strToList(props.getStrVal(pswsProp));
		if(logins.size() == 0 || logins.size() != psws.size()){
			throw new IllegalStateException("can't init users with invalid data:"+logins+", "+psws);
		}

		ArrayList<Long> ids = new ArrayList<>();
		for (int i = 0; i < logins.size(); i++) {
			String login = logins.get(i);
			String psw = psws.get(i);
			String email = login + "@system";
			long id = users.createUser(new User(login, email), psw, false);
			users.activateUser(id);
			users.setRoles(id, set(roles));
			log.info("created init user ["+login+"] with roles: "+set(roles));
			ids.add(id);
		}
		return ids;
	}

	public static FrontApp create(Props props, ServletContext servletContext) throws Exception {
		return create(props, servletContext, null, null);
	}

	public static FrontApp create(
			Props props,
			ServletContext servletContext,
			MailService mails,
			PaypalClient paypalClient) throws Exception {

		DataSource ds = BaseDb.createDataSource(props);
		MainDb db = new MainDb(ds, props);
		AsyncService async = new AsyncService();
		EventService events = new EventService();
		CacheClient cache = new CacheClient(props);
		Templates templates = new Templates(props);
		Captcha captcha = new Captcha(props);

		if(mails == null) mails = new MailService(props);
		if(paypalClient == null && ! props.getBoolVal(paypal_enabled)) paypalClient = new PaypalClientStub();
		if(paypalClient == null) paypalClient = props.getBoolVal(paypal_clientStub) ?
				new PaypalClientStub() : PaypalSoapClient.create(props);

		ToCheckoutProvider toCheckoutProvider = new ToCheckoutProvider(props);
		GeoIp geoIp = new GeoIp(props.getStrVal(geo_ip_dbPath), props.getBoolVal(geo_ip_dbInRAM));

		addUpdateSecureKeyListener(props, cache, cache_encyptedKey);

		FrontAppContext context = new FrontAppContext(
				props,
				async,
				events,
				db,
				cache,
				mails,
				templates,
				captcha,
				paypalClient,
				toCheckoutProvider,
				geoIp);

		FrontApp out = new FrontApp(context);
		out.security.init(servletContext);

		return out;
	}

}


text:
<?php namespace Falafel\HTTP;

interface ResponseInterface
{

	/**
	 * @note Writes to STDOUT
	 * @note Must also output any HTTP headers
	 */
	public function send();

	/**
	 * @param Callable $callback
	 * @return void
	 */
	public function setBodyCallback($callback);
}


text:
<title>gcloud compute target-pools add-health-checks</title>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<meta name="project_path" value="/sdk/_project.yaml">
<meta name="book_path" value="/sdk/_book.yaml">

NAME

gcloud compute target-pools add-health-checks - add an HTTP health check to a target pool

SYNOPSIS

gcloud compute target-pools add-health-checks NAME --http-health-check HEALTH_CHECK [--region REGION] [GLOBAL-FLAG …]

DESCRIPTION

gcloud compute target-pools add-health-checks is used to add an HTTP health check
to a target pool. Health checks are used to determine
the health status of instances in the target pool. Only one
health check can be attached to a target pool, so this command
will fail if there as already a health check attached to the target
pool. For more information on health checks and load balancing, see
https://developers.google.com/compute/docs/load-balancing/.

POSITIONAL ARGUMENTS

<var>NAME</var>

The name of the target pool to which to add the health check.

FLAGS

--http-health-check <var>HEALTH_CHECK</var>

Specifies an HTTP health check object to add to the target pool.

--region <var>REGION</var>

The region of the target pool to add health checks to. If not specified, you will be prompted to select a region.

To avoid prompting when this flag is omitted, you can set the
<var>compute/region</var> property:

$ gcloud config set compute/region REGION

A list of regions can be fetched by running:

$ gcloud compute regions list

To unset the property, run:

$ gcloud config unset compute/region

Alternatively, the region can be stored in the environment
variable <var>CLOUDSDK_COMPUTE_REGION</var>.

GLOBAL FLAGS

Run $ gcloud help for a description of flags available to
all commands.

NOTES

This command is in the Google Cloud SDK compute component. See
installing components
if it is not installed.


text:
@interface CUSINAClient ()

@property (nonatomic, strong) SinaWeibo *sinaweiboSDK;
@property (nonatomic, strong) void (^successBlock)(NSString *message, id data);
@property (nonatomic, strong) void (^failedBlock)( NSString *message, id data);

@property (nonatomic, strong) ASIHTTPRequest *request;

@end

@implementation CUSINAClient

- (id)initWithPlatForm:(PlatFormModel *)model
{
    if (self = [super init]) {
        self.sinaweiboSDK = [[SinaWeibo alloc] initWithAppKey:model.appKey
                                                    appSecret:model.appSecret
                                               appRedirectURI:model.redirectUri
                                            ssoCallbackScheme:nil
                                                  andDelegate:self];

        [self refreshTokenFromDisk];
    }

    return self;
}

- (void)refreshTokenFromDisk
{
    NSString *accessToken = [[NSUserDefaults standardUserDefaults] objectForKey:SINA_ACCESSTOKEN_KEY];
    NSString *uid = [[NSUserDefaults standardUserDefaults] objectForKey:SINA_USERID_KEY];
    NSDate *experationDate = [[NSUserDefaults standardUserDefaults] objectForKey:SINA_EXPIRATIONDATE_KEY];

    if (accessToken != nil) {
        self.sinaweiboSDK.accessToken = accessToken;
        self.sinaweiboSDK.userID = uid;
        self.sinaweiboSDK.expirationDate = experationDate;
    }
}

#pragma mark - Bind/unBind

- (void)bindSuccess:(void (^)(NSString *message, id data))success error:(void (^)(NSString *message, id data))errorBlock
{
    self.successBlock = [success copy];
    self.failedBlock = [errorBlock copy];

    [[NSNotificationCenter defaultCenter] addObserver:self
                                             selector:@selector(handleLoginNotification:)
                                                 name:NOTIFICATION_SINA_LOGIN_SUCCESS
                                               object:nil];

    [[NSNotificationCenter defaultCenter] addObserver:self
                                             selector:@selector(handleLoginNotification:)
                                                 name:NOTIFICATION_SINA_LOGIN_FALIED
                                               object:nil];

    [self.sinaweiboSDK logIn];
}

- (void)unBind
{
    self.successBlock = nil;
    self.failedBlock = nil;

    [self.sinaweiboSDK logOut];

    [[NSUserDefaults standardUserDefaults] removeObjectForKey:SINA_ACCESSTOKEN_KEY];
    [[NSUserDefaults standardUserDefaults] removeObjectForKey:SINA_USERID_KEY];
    [[NSUserDefaults standardUserDefaults] removeObjectForKey:SINA_EXPIRATIONDATE_KEY];

    [[NSUserDefaults standardUserDefaults] synchronize];
}

- (BOOL)isBind
{
    return [self.sinaweiboSDK isLoggedIn];
}

#pragma mark - userInfo

- (CUPlatFormOAuth *)OAuthInfo
{
    if (![self.sinaweiboSDK isAuthValid]) {
        return nil;
    }

    CUPlatFormOAuth *info = [CUPlatFormOAuth new];

    info.userId = self.sinaweiboSDK.userID;
    info.accessToken = self.sinaweiboSDK.accessToken;

    return info;
}

- (void)userInfoSuccess:(void (^)(CUPlatFormUserModel *model))success error:(void (^)(id data))errorBlock
{
    [self.request clearDelegatesAndCancel];
    self.request = [self requestUserInfoSuccess:success error:errorBlock];
    [self.request startAsynchronous];
}

- (ASIHTTPRequest *)requestUserInfoSuccess:(void (^)(CUPlatFormUserModel *model))success error:(void (^)(id data))errorBlock
{
    if (!self.sinaweiboSDK.isAuthValid) {
        return nil;
    }

    NSString *accessToken = self.sinaweiboSDK.accessToken;
    NSString *uid = self.sinaweiboSDK.userID;

    NSAssert(accessToken, @"accessToken nil");
    NSAssert(uid, @"uid nil");

    ASIHTTPRequest *request =
    [[CUSinaAPIClient shareObjectManager] getJSONRequestAtPath:@"2/users/show.json"
                                                    parameters:@{
                                                                 @"access_token" : accessToken,
                                                                 @"uid" : uid
                                                                 }
                                                       success:^(ASIHTTPRequest *ASIRequest, id json) {

                                                           CUPlatFormUserModel *model = [CUPlatFormUserModel new];
                                                           model.userId = self.sinaweiboSDK.userID;
                                                           model.nickname = json[@"screen_name"];
                                                           model.avatar = json[@"avatar_hd"];
                                                           model.platform = @"新浪微博";
                                                           model.orginalData = json;
                                                           model.gender = json[@"gender"];
                                                           if ([model.gender isEqualToString:@"m"]) {
                                                               model.gender = @"男";
                                                           }
                                                           else
                                                           {
                                                               model.gender = @"女";
                                                           }

                                                           success(model);

                                                       } error:^(ASIHTTPRequest *ASIRequest, NSString *errorMsg) {
                                                           errorBlock(ASIRequest.responseString);
                                                       }];
    return request;
}

#pragma mark - share

- (void)content:(NSString *)content success:(void (^)(id data))success
           error:(void (^)(id error))errorBlock
{
    [self.request clearDelegatesAndCancel];

    self.request = [self requestContent:content
                               imageURL:nil
                                success:^(id data) {

                                } error:^(id error) {

                                }];
}

- (void)content:(NSString *)content
      imageData:(NSData *)imageData
        success:(void (^)(id data))success
          error:(void (^)(id error))errorBlock
{
    [self.request clearDelegatesAndCancel];
    self.request = [self requestContent:content imageData:imageData success:success error:errorBlock];
    [self.request startAsynchronous];
}

- (void)content:(NSString *)content
       imageURL:(NSString *)imageURL
        success:(void (^)(id data))success
          error:(void (^)(id error))errorBlock
{
    [self.request clearDelegatesAndCancel];
    self.request = [self requestContent:content imageURL:imageURL success:success error:errorBlock];
    [self.request startAsynchronous];
}

- (ASIHTTPRequest *)requestContent:(NSString *)content
                          imageURL:(NSString *)imageURL
                           success:(void (^)(id data))success
                             error:(void (^)(id error))errorBlock
{
    NSAssert(FALSE, @"not @implement 新浪高级授权接口");
    return nil;
}

- (ASIHTTPRequest *)requestContent:(NSString *)content
                         imageData:(NSData *)imageData
                           success:(void (^)(id data))success
                             error:(void (^)(id error))errorBlock
{
    if (!self.sinaweiboSDK.isAuthValid) {
        return nil;
    }

    NSString *accessToken = self.sinaweiboSDK.accessToken;
    NSAssert(accessToken, @"accessToken nil");

    ASIHTTPRequest *request = [[CUSinaAPIClient shareObjectManager] postJSONRequestAtPath:@"2/statuses/upload.json"
                                                                                userBlock:^(ASIFormDataRequest *ASIRequest) {
                                                                                [ASIRequest addPostValue:content forKey:@"status"];
                                                                                [ASIRequest setPostValue:accessToken forKey:@"access_token"];
                                                                                [ASIRequest addData:imageData forKey:@"pic"];

                                                                                } success:^(ASIHTTPRequest *ASIRequest, id json) {
                                                                                success(json);
                                                                                } error:^(ASIHTTPRequest *ASIRequest, NSString *errorMsg) {
                                                                                errorBlock(errorMsg);
                                                                                }];

    return request;
}

- (void)clear
{
    self.sinaweiboSDK.delegate = nil;
    self.successBlock = nil;
    self.failedBlock = nil;

    [self.request clearDelegatesAndCancel];

    [[NSNotificationCenter defaultCenter] removeObserver:self];
}

- (BOOL)openURL:(NSURL *)url sourceApplication:(NSString *)sourceApplication annotation:(id)annotation
{
    if ([self.sinaweiboSDK isInstalled]) {
        self.sinaweiboSDK.ssoLoggingIn = YES;
    }

    return [self.sinaweiboSDK handleOpenURL:url];
}

#pragma mark - SinaWeiboDelegate

- (void)sinaweiboDidLogIn:(SinaWeibo *)sinaweibo
{
    [[NSUserDefaults standardUserDefaults] setObject:self.sinaweiboSDK.accessToken forKey:SINA_ACCESSTOKEN_KEY];
    [[NSUserDefaults standardUserDefaults] setObject:self.sinaweiboSDK.userID forKey:SINA_USERID_KEY];
    [[NSUserDefaults standardUserDefaults] setObject:self.sinaweiboSDK.expirationDate forKey:SINA_EXPIRATIONDATE_KEY];

    [[NSUserDefaults standardUserDefaults] synchronize];

    [[NSNotificationCenter defaultCenter] postNotificationName:NOTIFICATION_SINA_LOGIN_SUCCESS
                                                        object:self];
}

- (void)sinaweiboLogInDidCancel:(SinaWeibo *)sinaweibo
{
    [[NSNotificationCenter defaultCenter] postNotificationName:NOTIFICATION_SINA_LOGIN_FALIED
                                                        object:self];
}

- (void)sinaweibo:(SinaWeibo *)sinaweibo logInDidFailWithError:(NSError *)error
{
    [[NSNotificationCenter defaultCenter] postNotificationName:NOTIFICATION_SINA_LOGIN_FALIED
                                                        object:self];
}

- (void)sinaweibo:(SinaWeibo *)sinaweibo accessTokenInvalidOrExpired:(NSError *)error
{
    [[NSNotificationCenter defaultCenter] postNotificationName:NOTIFICATION_SINA_LOGIN_FALIED
                                                        object:self];
}

- (void)sinaweiboDidLogOut:(SinaWeibo *)sinaweibo
{
    if (self.successBlock) {
        self.successBlock(@"success", nil);
    }
}

#pragma mark - notification

- (void)handleLoginNotification:(NSNotification *)notify
{
    NSString *name = notify.name;
    if ([name isEqualToString:NOTIFICATION_SINA_LOGIN_SUCCESS]) {

        void (^successBlock)(NSString *message, id data) = [self.successBlock copy];
        [self clear];

        [self refreshTokenFromDisk];

        if (successBlock) {
            successBlock(@"success", nil);
        }

    }
    else if ([name isEqualToString:NOTIFICATION_SINA_LOGIN_FALIED])
    {
        if (self.failedBlock) {
            self.failedBlock(@"error", nil);
        }

        [self clear];
    }
}

@end


text:
package com.englishtown.vertx.jersey.promises.impl;

import com.englishtown.promises.Done;
import com.englishtown.promises.When;
import com.englishtown.promises.WhenFactory;
import com.englishtown.vertx.jersey.JerseyOptions;
import com.englishtown.vertx.jersey.JerseyServer;
import io.vertx.core.AsyncResult;
import io.vertx.core.Handler;
import io.vertx.core.Vertx;
import io.vertx.core.http.HttpServer;
import io.vertx.core.json.JsonObject;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.ArgumentCaptor;
import org.mockito.Captor;
import org.mockito.Mock;
import org.mockito.runners.MockitoJUnitRunner;

import static org.mockito.Matchers.eq;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;

/**
 * Unit tests for {@link DefaultWhenJerseyServer}
 */
@RunWith(MockitoJUnitRunner.class)
public class DefaultWhenJerseyServerTest {

    private DefaultWhenJerseyServer whenJerseyServer;
    JsonObject config = new JsonObject();
    private Done<JerseyServer> done = new Done<>();

    @Mock
    JerseyServer server;
    @Mock
    JerseyOptions options;
    @Mock
    Vertx vertx;
    @Mock
    AsyncResult<HttpServer> result;
    @Captor
    ArgumentCaptor<Handler<AsyncResult<HttpServer>>> handlerCaptor;

    @Before
    public void setUp() {
        When when = WhenFactory.createSync();
        whenJerseyServer = new DefaultWhenJerseyServer(vertx, server, options, when);
    }

    @Test
    public void testCreateServer_Success() throws Exception {

        when(result.succeeded()).thenReturn(true);

        whenJerseyServer.createServer(config)
                .then(done.onFulfilled, done.onRejected);

        verify(options).init(eq(config), eq(vertx));
        verify(server).init(eq(options), handlerCaptor.capture());

        handlerCaptor.getValue().handle(result);
        done.assertFulfilled();

    }

    @Test
    public void testCreateServer_Fail() throws Exception {

        when(result.succeeded()).thenReturn(false);

        whenJerseyServer.createServer(config)
                .then(done.onFulfilled, done.onRejected);

        verify(options).init(eq(config), eq(vertx));
        verify(server).init(eq(options), handlerCaptor.capture());

        handlerCaptor.getValue().handle(result);
        done.assertRejected();

    }

}


text:
require File.expand_path(File.dirname(__FILE__) + '/spec_helper')

describe Kindai::Spread do
  before do
    @book = Kindai::Book.new_from_permalink('http://kindai.ndl.go.jp/info:ndljp/pid/922693')
    @spread = @book.spreads[4]
  end

  it 'has spread number' do
    @spread.spread_number.should == 5
  end

  it 'has book' do
    @spread.book.should == @book
  end

  it 'has uri' do
    @spread.uri.should == 'http://kindai.ndl.go.jp/info:ndljp/pid/922693/5'
  end

  it 'has image_uri' do
    @spread.image_uri.should == "http://kindai.ndl.go.jp/view/jpegOutput?itemId=info%3Andljp%2Fpid%2F922693&contentNo=5&outputScale=1"
  end

end


text:
package me.williamhester.knapsack;

import android.os.Bundle;
import android.util.Log;

import java.util.LinkedHashMap;
import java.util.Map;

import me.williamhester.knapsack.internal.KnapsackProcessor;

/**
 * @author William Hester
 */
@SuppressWarnings("unused")
public class Knapsack {

    private static final String TAG = "Knapsack";

    private static final String JAVA_PREFIX = "java.";
    private static final String ANDROID_PREFIX = "android.";

    private static final boolean debug = false;

    private static final Map<Class<?>, Bundler> BUNDLERS = new LinkedHashMap<>();

    /**
     * This method saves the state of the Activity or Fragment that it is placed inside of. It only
     * needs to be invoked from the superclass and all of its child classes will be saved as well.
     *
     * @param target the Fragment or Activity instance
     * @param state the bundle to be saved into.
     */
    public static void save(Object target, Bundle state) {
        try {
            Bundler bundler = getBundlerForClass(target.getClass());
            bundler.save(state, target);
        } catch (IllegalAccessException | InstantiationException e) {
            e.printStackTrace();
        }
    }

    /**
     * This method restores the state of the Activity or Fragment that it is placed inside of. It
     * only needs to be invoked from the superclass and all of its child classes will be saved as
     * well.
     *
     * @param target the Fragment or Activity to restore.
     * @param state the saved instance state to populate the Fragment or Activity with
     * @return true if the state was restored.
     */
    public static boolean restore(Object target, Bundle state) {
        if (state == null) {
            return false;
        }
        try {
            Bundler bundler = getBundlerForClass(target.getClass());
            bundler.restore(state, target);
        } catch (IllegalAccessException | InstantiationException e) {
            e.printStackTrace();
        }
        return true;
    }

    private static Bundler getBundlerForClass(Class<?> cls)
            throws IllegalAccessException, InstantiationException {
        Bundler viewBinder = BUNDLERS.get(cls);
        if (viewBinder != null) {
            if (debug) Log.d(TAG, "HIT: Cached in view binder map.");
            return viewBinder;
        }
        String clsName = cls.getName();
        if (clsName.startsWith(ANDROID_PREFIX) || clsName.startsWith(JAVA_PREFIX)) {
            if (debug) Log.d(TAG, "MISS: Reached framework class. Abandoning search.");
            return NOP_BUNDLER;
        }
        try {
            Class<?> viewBindingClass = Class.forName(clsName + KnapsackProcessor.SUFFIX);
            //noinspection unchecked
            viewBinder = (Bundler) viewBindingClass.newInstance();
            if (debug) Log.d(TAG, "HIT: Loaded view binder class.");
        } catch (ClassNotFoundException e) {
            if (debug) Log.d(TAG, "Not found. Trying superclass " + cls.getSuperclass().getName());
            viewBinder = getBundlerForClass(cls.getSuperclass());
        }
        BUNDLERS.put(cls, viewBinder);
        return viewBinder;
    }

    private static Bundler createBundler() {
        return null;
    }

    private static final Bundler NOP_BUNDLER = new Bundler() {
        @Override
        public void save(Bundle state, Object target) { }

        @Override
        public void restore(Bundle state, Object target) { }
    };

}


text:
require 'spec_helper'
require 'rack/mock'

require 'rollbar/request_data_extractor'

class ExtractorDummy
  include Rollbar::RequestDataExtractor
end

describe Rollbar::RequestDataExtractor do
  subject { ExtractorDummy.new }

  let(:env) do
    Rack::MockRequest.env_for('/', 'HTTP_HOST' => 'localhost:81',
                                   'HTTP_X_FORWARDED_HOST' => 'example.org:9292')
  end

  describe '#scrub_url' do
    let(:url) { 'http://this-is-the-url.com/foobar?param1=value1' }
    let(:sensitive_params) { [:param1, :param2] }
    let(:scrub_fields) { [:password, :secret] }
    let(:scrub_whitelist) { false }

    before do
      allow(Rollbar.configuration).to receive(:scrub_fields).and_return(scrub_fields)
      allow(Rollbar.configuration).to receive(:scrub_user).and_return(true)
      allow(Rollbar.configuration).to receive(:scrub_password).and_return(true)
      allow(Rollbar.configuration).to receive(:randomize_secret_length).and_return(true)
      allow(Rollbar.configuration).to receive(:scrub_whitelist).and_return(false)
    end

    it 'calls the scrubber with the correct options' do
      expected_options = {
        :url => url,
        :scrub_fields => [:password, :secret, :param1, :param2],
        :scrub_user => true,
        :scrub_password => true,
        :randomize_scrub_length => false,
        :whitelist => false
      }

      expect(Rollbar::Scrubbers::URL).to receive(:call).with(expected_options)

      subject.scrub_url(url, sensitive_params)
    end
  end

  describe '#scrub_params' do
    let(:params) do
      {
        :param1 => 'value1',
        :param2 => 'value2'
      }
    end
    let(:sensitive_params) { [:param1, :param2] }
    let(:scrub_fields) { [:password, :secret] }
    let(:scrub_whitelist) { false }

    before do
      allow(Rollbar.configuration).to receive(:scrub_fields)
        .and_return(scrub_fields)
      allow(Rollbar.configuration).to receive(:scrub_whitelist)
        .and_return(scrub_whitelist)
    end

    it 'calls the scrubber with the correct options' do
      expected_options = {
        :params => params,
        :config => scrub_fields,
        :extra_fields => sensitive_params,
        :whitelist => scrub_whitelist
      }

      expect(Rollbar::Scrubbers::Params).to receive(:call).with(expected_options)

      subject.scrub_params(params, sensitive_params)
    end
  end

  describe '#extract_request_data_from_rack' do
    it 'returns a Hash object' do
      expect(Rollbar::Scrubbers::URL).to receive(:call)
        .with(kind_of(Hash))
        .and_call_original
      expect(Rollbar::Scrubbers::Params).to receive(:call)
        .with(kind_of(Hash))
        .and_call_original.exactly(6)

      result = subject.extract_request_data_from_rack(env)

      expect(result).to be_kind_of(Hash)
    end

    context 'with scrub headers set' do
      let(:scrub_headers) do
        %w[HTTP_UPPER_CASE_HEADER http-lower-case-header Mixed-CASE-header]
      end

      let(:env) do
        Rack::MockRequest.env_for('/',
                                  'HTTP_UPPER_CASE_HEADER' => 'foo',
                                  'HTTP_LOWER_CASE_HEADER' => 'bar',
                                  'HTTP_MIXED_CASE_HEADER' => 'baz')
      end

      before do
        allow(Rollbar.configuration).to receive(:scrub_headers)
          .and_return(scrub_headers)
      end

      it 'returns scrubbed headers' do
        result = subject.extract_request_data_from_rack(env)
        headers = result[:headers]

        expect(headers['Upper-Case-Header']).to match(/^\*+$/)
        expect(headers['Lower-Case-Header']).to match(/^\*+$/)
        expect(headers['Mixed-Case-Header']).to match(/^\*+$/)
      end
    end

    context 'with invalid utf8 sequence in key' do
      let(:data) do
        File.read(File.expand_path('../../support/encodings/iso_8859_9',
                                   __FILE__)).force_encoding(Encoding::ISO_8859_9)
      end
      let(:env) do
        env = Rack::MockRequest.env_for('/',
                                        'HTTP_HOST' => 'localhost:81',
                                        'HTTP_X_FORWARDED_HOST' => 'example.org:9292',
                                        'CONTENT_TYPE' => 'application/json')

        env['rack.session'] = { data => 'foo' }
        env
      end

      it 'doesnt crash' do
        result = subject.extract_request_data_from_rack(env)

        expect(result).to be_kind_of(Hash)
      end

      context 'with CONTENT_TYPE and CONTENT_LENGTH headers' do
        let(:env) do
          Rack::MockRequest.env_for('/',
                                    'HTTP_HOST' => 'localhost:81',
                                    'HTTP_X_FORWARDED_HOST' => 'example.org:9292',
                                    'CONTENT_TYPE' => 'application/json',
                                    'CONTENT_LENGTH' => 20)
        end

        it 'adds the content type header to the headers key' do
          result = subject.extract_request_data_from_rack(env)

          expect(result[:headers]['Content-Type']).to be_eql('application/json')
          expect(result[:headers]['Content-Length']).to be_eql(20)
        end
      end
    end

    context 'with multiple IP addresses in headers and in user ip' do
      let(:env) do
        Rack::MockRequest.env_for('/',
                                  'HTTP_HOST' => 'localhost:81',
                                  'HTTP_X_FORWARDED_FOR' => x_forwarded_for,
                                  'HTTP_X_REAL_IP' => x_real_ip,
                                  'HTTP_CF_CONNECTING_IP' => cf_connecting_ip,
                                  'REMOTE_ADDR' => '3.3.3.3',
                                  'CONTENT_TYPE' => 'application/json',
                                  'CONTENT_LENGTH' => 20)
      end
      let(:cf_connecting_ip) { '4.3.2.1' }

      context 'with public client IP' do
        let(:x_forwarded_for) { '2.2.2.2, 3.3.3.3' }
        let(:x_real_ip) { '2.2.2.2' }

        it 'extracts the correct user IP' do
          result = subject.extract_request_data_from_rack(env)

          expect(result[:user_ip]).to be_eql('2.2.2.2')
        end

        it 'extracts the correct X-Forwarded-For' do
          result = subject.extract_request_data_from_rack(env)

          expect(result[:headers]['X-Forwarded-For']).to be_eql('2.2.2.2, 3.3.3.3')
        end

        it 'extracts the correct X-Real-Ip' do
          result = subject.extract_request_data_from_rack(env)

          expect(result[:headers]['X-Real-Ip']).to be_eql('2.2.2.2')
        end

        context 'with config.user_ip_rack_env_key set' do
          before do
            Rollbar.configuration.user_ip_rack_env_key = 'HTTP_CF_CONNECTING_IP'
          end

          it 'extracts from the correct key' do
            result = subject.extract_request_data_from_rack(env)

            expect(result[:user_ip]).to be_eql(cf_connecting_ip)
          end
        end

        context 'with collect_user_ip configuration option disabled' do
          before do
            Rollbar.configuration.collect_user_ip = false
          end

          it 'does not extract user\'s IP' do
            result = subject.extract_request_data_from_rack(env)

            expect(result[:user_ip]).to be_nil
          end

          it 'does not extract user\'s IP on X-Forwarded-For header' do
            result = subject.extract_request_data_from_rack(env)

            expect(result[:headers]['X-Forwarded-For']).to be_nil
          end

          it 'does not extract user\'s IP on X-Real-Ip header' do
            result = subject.extract_request_data_from_rack(env)

            expect(result[:headers]['X-Real-Ip']).to be_nil
          end
        end

        context 'with anonymize_user_ip configuration option enabled' do
          before do
            Rollbar.configuration.anonymize_user_ip = true
          end

          it 'it anonymizes the IPv4 address' do
            result = subject.extract_request_data_from_rack(env)

            expect(result[:user_ip]).to be_eql('2.2.2.0')
          end

          it 'it anonymizes IP addresses in X-Forwarded-For' do
            result = subject.extract_request_data_from_rack(env)

            expect(result[:headers]['X-Forwarded-For']).to be_eql('2.2.2.0, 3.3.3.0')
          end

          it 'it anonymizes IP addresses in X-Real-Ip' do
            result = subject.extract_request_data_from_rack(env)

            expect(result[:headers]['X-Real-Ip']).to be_eql('2.2.2.0')
          end
        end
      end

      context 'with private first client IP' do
        let(:x_forwarded_for) { '192.168.1.1, 2.2.2.2, 3.3.3.3' }
        let(:x_real_ip) { '2.2.2.2' }

        it 'extracts the correct user IP' do
          result = subject.extract_request_data_from_rack(env)

          expect(result[:user_ip]).to be_eql('2.2.2.2')
        end

        it 'extracts the correct X-Forwarded-For' do
          result = subject.extract_request_data_from_rack(env)

          expect(result[:headers]['X-Forwarded-For'])
            .to be_eql('192.168.1.1, 2.2.2.2, 3.3.3.3')
        end

        it 'extracts the correct X-Real-Ip' do
          result = subject.extract_request_data_from_rack(env)

          expect(result[:headers]['X-Real-Ip']).to be_eql('2.2.2.2')
        end
      end
    end

    context 'with form POST body (non-json)' do
      let(:body) { 'foo=1&bar=2' }
      let(:env) do
        Rack::MockRequest.env_for('/?foo=bar',
                                  'CONTENT_TYPE' => 'application/x-www-form-urlencoded',
                                  'HTTP_ACCEPT' => 'application/json',
                                  :input => body,
                                  :method => 'POST')
      end

      it 'skips extracting the body' do
        result = subject.extract_request_data_from_rack(env)
        expect(result[:body]).to be_eql('{}')
      end
    end

    context 'with JSON POST body' do
      let(:params) { { 'key' => 'value' } }
      let(:body) { params.to_json }
      let(:env) do
        Rack::MockRequest.env_for('/?foo=bar',
                                  'CONTENT_TYPE' => 'application/json',
                                  :input => body,
                                  :method => 'POST')
      end

      it 'extracts the correct body' do
        result = subject.extract_request_data_from_rack(env)
        expect(result[:body]).to be_eql(body)
      end

      it 'extracts the correct body for JSONAPI' do
        env['CONTENT_TYPE'] = 'application/vnd.api+json'
        result = subject.extract_request_data_from_rack(env)
        expect(result[:body]).to be_eql(body)
      end

      it 'extracts the correct body for any JSON compatible MIME type' do
        env['CONTENT_TYPE'] = 'application/ld+json'
        result = subject.extract_request_data_from_rack(env)
        expect(result[:body]).to be_eql(body)
      end
    end

    context 'with JSON DELETE body' do
      let(:params) { { 'key' => 'value' } }
      let(:body) { params.to_json }
      let(:env) do
        Rack::MockRequest.env_for('/?foo=bar',
                                  'CONTENT_TYPE' => 'application/json',
                                  :input => body,
                                  :method => 'DELETE')
      end

      it 'extracts the correct body' do
        result = subject.extract_request_data_from_rack(env)
        expect(result[:body]).to be_eql(body)
      end
    end

    context 'with JSON PUT body' do
      let(:params) { { 'key' => 'value' } }
      let(:body) { params.to_json }
      let(:env) do
        Rack::MockRequest.env_for('/?foo=bar',
                                  'CONTENT_TYPE' => 'application/json',
                                  :input => body,
                                  :method => 'PUT')
      end

      it 'extracts the correct body' do
        result = subject.extract_request_data_from_rack(env)
        expect(result[:body]).to be_eql(body)
      end
    end

    context 'with non-rewindable input' do
      let(:params) { { 'key' => 'value' } }
      let(:body) { params.to_json }
      let(:env) do
        Rack::MockRequest.env_for('/?foo=bar',
                                  'CONTENT_TYPE' => 'application/json',
                                  :method => 'POST')
      end

      # According to Rack 3.0 "The input stream must respond to gets, each, and read"
      # https://github.com/rack/rack/blob/3.0.0/SPEC.rdoc#the-input-stream-
      let(:non_rewindable_input) do
        Class.new do
          def initialize(body)
            @body = body
          end

          def gets
            @body
          end

          def read
            @body
          end

          def each
            yield(@body)
          end
        end
      end

      before do
        env['rack.input'] = non_rewindable_input.new(body)
      end

      it 'skips extracting the body' do
        result = subject.extract_request_data_from_rack(env)
        expect(result[:body]).to be_eql('{}')
      end
    end

    context 'with POST params' do
      let(:params) { { 'key' => 'value' } }
      let(:env) do
        Rack::MockRequest.env_for('/?foo=bar',
                                  :params => params,
                                  :method => 'POST')
      end

      it 'extracts the correct user IP' do
        result = subject.extract_request_data_from_rack(env)
        expect(result[:POST]).to be_eql(params)
      end
    end

    context 'with GET params' do
      let(:params) { { 'key' => 'value' } }
      let(:env) do
        Rack::MockRequest.env_for('/?foo=bar',
                                  :params => params,
                                  :method => 'GET')
      end

      it 'extracts the correct user IP' do
        result = subject.extract_request_data_from_rack(env)
        expect(result[:GET]).to be_eql(params)
      end
    end
  end
end