text:
// Copyright (c) 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

// Histogram is an object that aggregates statistics, and can summarize them in
// various forms, including ASCII graphical, HTML, and numerically (as a
// vector of numbers corresponding to each of the aggregating buckets).

// It supports calls to accumulate either time intervals (which are processed
// as integral number of milliseconds), or arbitrary integral units.

// For Histogram(exponential histogram), LinearHistogram and CustomHistogram,
// the minimum for a declared range is 1 (instead of 0), while the maximum is
// (HistogramBase::kSampleType_MAX - 1). Currently you can declare histograms
// with ranges exceeding those limits (e.g. 0 as minimal or
// HistogramBase::kSampleType_MAX as maximal), but those excesses will be
// silently clamped to those limits (for backwards compatibility with existing
// code). Best practice is to not exceed the limits.

// Each use of a histogram with the same name will reference the same underlying
// data, so it is safe to record to the same histogram from multiple locations
// in the code. It is a runtime error if all uses of the same histogram do not
// agree exactly in type, bucket size and range.

// For Histogram and LinearHistogram, the maximum for a declared range should
// always be larger (not equal) than minmal range. Zero and
// HistogramBase::kSampleType_MAX are implicitly added as first and last ranges,
// so the smallest legal bucket_count is 3. However CustomHistogram can have
// bucket count as 2 (when you give a custom ranges vector containing only 1
// range).
// For these 3 kinds of histograms, the max bucket count is always
// (Histogram::kBucketCount_MAX - 1).

// The buckets layout of class Histogram is exponential. For example, buckets
// might contain (sequentially) the count of values in the following intervals:
// [0,1), [1,2), [2,4), [4,8), [8,16), [16,32), [32,64), [64,infinity)
// That bucket allocation would actually result from construction of a histogram
// for values between 1 and 64, with 8 buckets, such as:
// Histogram count("some name", 1, 64, 8);
// Note that the underflow bucket [0,1) and the overflow bucket [64,infinity)
// are also counted by the constructor in the user supplied "bucket_count"
// argument.
// The above example has an exponential ratio of 2 (doubling the bucket width
// in each consecutive bucket.  The Histogram class automatically calculates
// the smallest ratio that it can use to construct the number of buckets
// selected in the constructor.  An another example, if you had 50 buckets,
// and millisecond time values from 1 to 10000, then the ratio between
// consecutive bucket widths will be approximately somewhere around the 50th
// root of 10000.  This approach provides very fine grain (narrow) buckets
// at the low end of the histogram scale, but allows the histogram to cover a
// gigantic range with the addition of very few buckets.

// Usually we use macros to define and use a histogram. These macros use a
// pattern involving a function static variable, that is a pointer to a
// histogram.  This static is explicitly initialized on any thread
// that detects a uninitialized (NULL) pointer.  The potentially racy
// initialization is not a problem as it is always set to point to the same
// value (i.e., the FactoryGet always returns the same value).  FactoryGet
// is also completely thread safe, which results in a completely thread safe,
// and relatively fast, set of counters.  To avoid races at shutdown, the static
// pointer is NOT deleted, and we leak the histograms at process termination.

#ifndef BASE_METRICS_HISTOGRAM_H_
#define BASE_METRICS_HISTOGRAM_H_

#include <map>
#include <string>
#include <vector>

#include "base/atomicops.h"
#include "base/base_export.h"
#include "base/basictypes.h"
#include "base/compiler_specific.h"
#include "base/gtest_prod_util.h"
#include "base/logging.h"
#include "base/memory/scoped_ptr.h"
#include "base/metrics/bucket_ranges.h"
#include "base/metrics/histogram_base.h"
#include "base/metrics/histogram_samples.h"
#include "base/time.h"

class Pickle;
class PickleIterator;

namespace base {

class Lock;
//------------------------------------------------------------------------------
// Histograms are often put in areas where they are called many many times, and
// performance is critical.  As a result, they are designed to have a very low
// recurring cost of executing (adding additional samples).  Toward that end,
// the macros declare a static pointer to the histogram in question, and only
// take a "slow path" to construct (or find) the histogram on the first run
// through the macro.  We leak the histograms at shutdown time so that we don't
// have to validate using the pointers at any time during the running of the
// process.

// The following code is generally what a thread-safe static pointer
// initializaion looks like for a histogram (after a macro is expanded).  This
// sample is an expansion (with comments) of the code for
// HISTOGRAM_CUSTOM_COUNTS().

/*
  do {
    // The pointer's presence indicates the initialization is complete.
    // Initialization is idempotent, so it can safely be atomically repeated.
    static base::subtle::AtomicWord atomic_histogram_pointer = 0;

    // Acquire_Load() ensures that we acquire visibility to the pointed-to data
    // in the histogrom.
    base::Histogram* histogram_pointer(reinterpret_cast<base::Histogram*>(
        base::subtle::Acquire_Load(&atomic_histogram_pointer)));

    if (!histogram_pointer) {
      // This is the slow path, which will construct OR find the matching
      // histogram.  FactoryGet includes locks on a global histogram name map
      // and is completely thread safe.
      histogram_pointer = base::Histogram::FactoryGet(
          name, min, max, bucket_count, base::HistogramBase::kNoFlags);

      // Use Release_Store to ensure that the histogram data is made available
      // globally before we make the pointer visible.
      // Several threads may perform this store, but the same value will be
      // stored in all cases (for a given named/spec'ed histogram).
      // We could do this without any barrier, since FactoryGet entered and
      // exited a lock after construction, but this barrier makes things clear.
      base::subtle::Release_Store(&atomic_histogram_pointer,
          reinterpret_cast<base::subtle::AtomicWord>(histogram_pointer));
    }

    // Ensure calling contract is upheld, and the name does NOT vary.
    DCHECK(histogram_pointer->histogram_name() == constant_histogram_name);

    histogram_pointer->Add(sample);
  } while (0);
*/

// The above pattern is repeated in several macros.  The only elements that
// vary are the invocation of the Add(sample) vs AddTime(sample), and the choice
// of which FactoryGet method to use.  The different FactoryGet methods have
// various argument lists, so the function with its argument list is provided as
// a macro argument here.  The name is only used in a DCHECK, to assure that
// callers don't try to vary the name of the histogram (which would tend to be
// ignored by the one-time initialization of the histogtram_pointer).
#define STATIC_HISTOGRAM_POINTER_BLOCK(constant_histogram_name, \
                                       histogram_add_method_invocation, \
                                       histogram_factory_get_invocation) \
  do { \
    static base::subtle::AtomicWord atomic_histogram_pointer = 0; \
    base::HistogramBase* histogram_pointer( \
        reinterpret_cast<base::HistogramBase*>( \
            base::subtle::Acquire_Load(&atomic_histogram_pointer))); \
    if (!histogram_pointer) { \
      histogram_pointer = histogram_factory_get_invocation; \
      base::subtle::Release_Store(&atomic_histogram_pointer, \
          reinterpret_cast<base::subtle::AtomicWord>(histogram_pointer)); \
    } \
    DCHECK_EQ(histogram_pointer->histogram_name(), \
              std::string(constant_histogram_name)); \
    histogram_pointer->histogram_add_method_invocation; \
  } while (0)

//------------------------------------------------------------------------------
// Provide easy general purpose histogram in a macro, just like stats counters.
// The first four macros use 50 buckets.

#define HISTOGRAM_TIMES(name, sample) HISTOGRAM_CUSTOM_TIMES( \
    name, sample, base::TimeDelta::FromMilliseconds(1), \
    base::TimeDelta::FromSeconds(10), 50)

// For folks that need real specific times, use this to select a precise range
// of times you want plotted, and the number of buckets you want used.
#define HISTOGRAM_CUSTOM_TIMES(name, sample, min, max, bucket_count) \
    STATIC_HISTOGRAM_POINTER_BLOCK(name, AddTime(sample), \
        base::Histogram::FactoryTimeGet(name, min, max, bucket_count, \
                                        base::HistogramBase::kNoFlags))

#define HISTOGRAM_COUNTS(name, sample) HISTOGRAM_CUSTOM_COUNTS( \
    name, sample, 1, 1000000, 50)

#define HISTOGRAM_COUNTS_100(name, sample) HISTOGRAM_CUSTOM_COUNTS( \
    name, sample, 1, 100, 50)

#define HISTOGRAM_COUNTS_10000(name, sample) HISTOGRAM_CUSTOM_COUNTS( \
    name, sample, 1, 10000, 50)

#define HISTOGRAM_CUSTOM_COUNTS(name, sample, min, max, bucket_count) \
    STATIC_HISTOGRAM_POINTER_BLOCK(name, Add(sample), \
        base::Histogram::FactoryGet(name, min, max, bucket_count, \
                                    base::HistogramBase::kNoFlags))

#define HISTOGRAM_PERCENTAGE(name, under_one_hundred) \
    HISTOGRAM_ENUMERATION(name, under_one_hundred, 101)

#define HISTOGRAM_BOOLEAN(name, sample) \
    STATIC_HISTOGRAM_POINTER_BLOCK(name, AddBoolean(sample), \
        base::BooleanHistogram::FactoryGet(name, base::Histogram::kNoFlags))

// Support histograming of an enumerated value.  The samples should always be
// strictly less than |boundary_value| -- this prevents you from running into
// problems down the line if you add additional buckets to the histogram.  Note
// also that, despite explicitly setting the minimum bucket value to |1| below,
// it is fine for enumerated histograms to be 0-indexed -- this is because
// enumerated histograms should never have underflow.
#define HISTOGRAM_ENUMERATION(name, sample, boundary_value) \
    STATIC_HISTOGRAM_POINTER_BLOCK(name, Add(sample), \
        base::LinearHistogram::FactoryGet(name, 1, boundary_value, \
            boundary_value + 1, base::HistogramBase::kNoFlags))

// Support histograming of an enumerated value. Samples should be one of the
// std::vector<int> list provided via |custom_ranges|. See comments above
// CustomRanges::FactoryGet about the requirement of |custom_ranges|.
// You can use the helper function CustomHistogram::ArrayToCustomRanges to
// transform a C-style array of valid sample values to a std::vector<int>.
#define HISTOGRAM_CUSTOM_ENUMERATION(name, sample, custom_ranges) \
    STATIC_HISTOGRAM_POINTER_BLOCK(name, Add(sample), \
        base::CustomHistogram::FactoryGet(name, custom_ranges, \
                                          base::HistogramBase::kNoFlags))

#define HISTOGRAM_MEMORY_KB(name, sample) HISTOGRAM_CUSTOM_COUNTS( \
    name, sample, 1000, 500000, 50)

//------------------------------------------------------------------------------
// Define Debug vs non-debug flavors of macros.
#ifndef NDEBUG

#define DHISTOGRAM_TIMES(name, sample) HISTOGRAM_TIMES(name, sample)
#define DHISTOGRAM_COUNTS(name, sample) HISTOGRAM_COUNTS(name, sample)
#define DHISTOGRAM_PERCENTAGE(name, under_one_hundred) HISTOGRAM_PERCENTAGE(\
    name, under_one_hundred)
#define DHISTOGRAM_CUSTOM_TIMES(name, sample, min, max, bucket_count) \
    HISTOGRAM_CUSTOM_TIMES(name, sample, min, max, bucket_count)
#define DHISTOGRAM_CLIPPED_TIMES(name, sample, min, max, bucket_count) \
    HISTOGRAM_CLIPPED_TIMES(name, sample, min, max, bucket_count)
#define DHISTOGRAM_CUSTOM_COUNTS(name, sample, min, max, bucket_count) \
    HISTOGRAM_CUSTOM_COUNTS(name, sample, min, max, bucket_count)
#define DHISTOGRAM_ENUMERATION(name, sample, boundary_value) \
    HISTOGRAM_ENUMERATION(name, sample, boundary_value)
#define DHISTOGRAM_CUSTOM_ENUMERATION(name, sample, custom_ranges) \
    HISTOGRAM_CUSTOM_ENUMERATION(name, sample, custom_ranges)

#else  // NDEBUG
// Keep a mention of passed variables to avoid unused variable warnings in
// release build if these variables are only used in macros.
#define DISCARD_2_ARGUMENTS(a, b) \
  while (0) { \
    static_cast<void>(a); \
    static_cast<void>(b); \
 }
#define DISCARD_3_ARGUMENTS(a, b, c) \
  while (0) { \
    static_cast<void>(a); \
    static_cast<void>(b); \
    static_cast<void>(c); \
 }
#define DISCARD_5_ARGUMENTS(a, b, c, d ,e) \
  while (0) { \
    static_cast<void>(a); \
    static_cast<void>(b); \
    static_cast<void>(c); \
    static_cast<void>(d); \
    static_cast<void>(e); \
 }
#define DHISTOGRAM_TIMES(name, sample) \
    DISCARD_2_ARGUMENTS(name, sample)

#define DHISTOGRAM_COUNTS(name, sample) \
    DISCARD_2_ARGUMENTS(name, sample)

#define DHISTOGRAM_PERCENTAGE(name, under_one_hundred) \
    DISCARD_2_ARGUMENTS(name, under_one_hundred)

#define DHISTOGRAM_CUSTOM_TIMES(name, sample, min, max, bucket_count) \
    DISCARD_5_ARGUMENTS(name, sample, min, max, bucket_count)

#define DHISTOGRAM_CLIPPED_TIMES(name, sample, min, max, bucket_count) \
    DISCARD_5_ARGUMENTS(name, sample, min, max, bucket_count)

#define DHISTOGRAM_CUSTOM_COUNTS(name, sample, min, max, bucket_count) \
    DISCARD_5_ARGUMENTS(name, sample, min, max, bucket_count)

#define DHISTOGRAM_ENUMERATION(name, sample, boundary_value) \
    DISCARD_3_ARGUMENTS(name, sample, boundary_value)

#define DHISTOGRAM_CUSTOM_ENUMERATION(name, sample, custom_ranges) \
    DISCARD_3_ARGUMENTS(name, sample, custom_ranges)

#endif  // NDEBUG

//------------------------------------------------------------------------------
// The following macros provide typical usage scenarios for callers that wish
// to record histogram data, and have the data submitted/uploaded via UMA.
// Not all systems support such UMA, but if they do, the following macros
// should work with the service.

#define UMA_HISTOGRAM_TIMES(name, sample) UMA_HISTOGRAM_CUSTOM_TIMES( \
    name, sample, base::TimeDelta::FromMilliseconds(1), \
    base::TimeDelta::FromSeconds(10), 50)

#define UMA_HISTOGRAM_MEDIUM_TIMES(name, sample) UMA_HISTOGRAM_CUSTOM_TIMES( \
    name, sample, base::TimeDelta::FromMilliseconds(10), \
    base::TimeDelta::FromMinutes(3), 50)

// Use this macro when times can routinely be much longer than 10 seconds.
#define UMA_HISTOGRAM_LONG_TIMES(name, sample) UMA_HISTOGRAM_CUSTOM_TIMES( \
    name, sample, base::TimeDelta::FromMilliseconds(1), \
    base::TimeDelta::FromHours(1), 50)

#define UMA_HISTOGRAM_CUSTOM_TIMES(name, sample, min, max, bucket_count) \
    STATIC_HISTOGRAM_POINTER_BLOCK(name, AddTime(sample), \
        base::Histogram::FactoryTimeGet(name, min, max, bucket_count, \
            base::HistogramBase::kUmaTargetedHistogramFlag))

#define UMA_HISTOGRAM_COUNTS(name, sample) UMA_HISTOGRAM_CUSTOM_COUNTS( \
    name, sample, 1, 1000000, 50)

#define UMA_HISTOGRAM_COUNTS_100(name, sample) UMA_HISTOGRAM_CUSTOM_COUNTS( \
    name, sample, 1, 100, 50)

#define UMA_HISTOGRAM_COUNTS_10000(name, sample) UMA_HISTOGRAM_CUSTOM_COUNTS( \
    name, sample, 1, 10000, 50)

#define UMA_HISTOGRAM_CUSTOM_COUNTS(name, sample, min, max, bucket_count) \
    STATIC_HISTOGRAM_POINTER_BLOCK(name, Add(sample), \
        base::Histogram::FactoryGet(name, min, max, bucket_count, \
            base::HistogramBase::kUmaTargetedHistogramFlag))

#define UMA_HISTOGRAM_MEMORY_KB(name, sample) UMA_HISTOGRAM_CUSTOM_COUNTS( \
    name, sample, 1000, 500000, 50)

#define UMA_HISTOGRAM_MEMORY_MB(name, sample) UMA_HISTOGRAM_CUSTOM_COUNTS( \
    name, sample, 1, 1000, 50)

#define UMA_HISTOGRAM_PERCENTAGE(name, under_one_hundred) \
    UMA_HISTOGRAM_ENUMERATION(name, under_one_hundred, 101)

#define UMA_HISTOGRAM_BOOLEAN(name, sample) \
    STATIC_HISTOGRAM_POINTER_BLOCK(name, AddBoolean(sample), \
        base::BooleanHistogram::FactoryGet(name, \
            base::HistogramBase::kUmaTargetedHistogramFlag))

// The samples should always be strictly less than |boundary_value|.  For more
// details, see the comment for the |HISTOGRAM_ENUMERATION| macro, above.
#define UMA_HISTOGRAM_ENUMERATION(name, sample, boundary_value) \
    STATIC_HISTOGRAM_POINTER_BLOCK(name, Add(sample), \
        base::LinearHistogram::FactoryGet(name, 1, boundary_value, \
            boundary_value + 1, base::HistogramBase::kUmaTargetedHistogramFlag))

#define UMA_HISTOGRAM_CUSTOM_ENUMERATION(name, sample, custom_ranges) \
    STATIC_HISTOGRAM_POINTER_BLOCK(name, Add(sample), \
        base::CustomHistogram::FactoryGet(name, custom_ranges, \
            base::HistogramBase::kUmaTargetedHistogramFlag))

//------------------------------------------------------------------------------

class BucketRanges;
class SampleVector;

class BooleanHistogram;
class CustomHistogram;
class Histogram;
class LinearHistogram;

class BASE_EXPORT Histogram : public HistogramBase {
 public:
  // Initialize maximum number of buckets in histograms as 16,384.
  static const size_t kBucketCount_MAX;

  typedef std::vector<Count> Counts;

  //----------------------------------------------------------------------------
  // For a valid histogram, input should follow these restrictions:
  // minimum > 0 (if a minimum below 1 is specified, it will implicitly be
  //              normalized up to 1)
  // maximum > minimum
  // buckets > 2 [minimum buckets needed: underflow, overflow and the range]
  // Additionally,
  // buckets <= (maximum - minimum + 2) - this is to ensure that we don't have
  // more buckets than the range of numbers; having more buckets than 1 per
  // value in the range would be nonsensical.
  static HistogramBase* FactoryGet(const std::string& name,
                                   Sample minimum,
                                   Sample maximum,
                                   size_t bucket_count,
                                   int32 flags);
  static HistogramBase* FactoryTimeGet(const std::string& name,
                                       base::TimeDelta minimum,
                                       base::TimeDelta maximum,
                                       size_t bucket_count,
                                       int32 flags);

  // Time call for use with DHISTOGRAM*.
  // Returns TimeTicks::Now() in debug and TimeTicks() in release build.
  static TimeTicks DebugNow();

  static void InitializeBucketRanges(Sample minimum,
                                     Sample maximum,
                                     size_t bucket_count,
                                     BucketRanges* ranges);

  // This constant if for FindCorruption. Since snapshots of histograms are
  // taken asynchronously relative to sampling, and our counting code currently
  // does not prevent race conditions, it is pretty likely that we'll catch a
  // redundant count that doesn't match the sample count.  We allow for a
  // certain amount of slop before flagging this as an inconsistency. Even with
  // an inconsistency, we'll snapshot it again (for UMA in about a half hour),
  // so we'll eventually get the data, if it was not the result of a corruption.
  static const int kCommonRaceBasedCountMismatch;

  // Check to see if bucket ranges, counts and tallies in the snapshot are
  // consistent with the bucket ranges and checksums in our histogram.  This can
  // produce a false-alarm if a race occurred in the reading of the data during
  // a SnapShot process, but should otherwise be false at all times (unless we
  // have memory over-writes, or DRAM failures).
  virtual int FindCorruption(const HistogramSamples& samples) const OVERRIDE;

  //----------------------------------------------------------------------------
  // Accessors for factory constuction, serialization and testing.
  //----------------------------------------------------------------------------
  Sample declared_min() const { return declared_min_; }
  Sample declared_max() const { return declared_max_; }
  virtual Sample ranges(size_t i) const;
  virtual size_t bucket_count() const;
  const BucketRanges* bucket_ranges() const { return bucket_ranges_; }

  // This function validates histogram construction arguments. It returns false
  // if some of the arguments are totally bad.
  // Note. Currently it allow some bad input, e.g. 0 as minimum, but silently
  // converts it to good input: 1.
  // TODO(kaiwang): Be more restrict and return false for any bad input, and
  // make this a readonly validating function.
  static bool InspectConstructionArguments(const std::string& name,
                                           Sample* minimum,
                                           Sample* maximum,
                                           size_t* bucket_count);

  // HistogramBase implementation:
  virtual HistogramType GetHistogramType() const OVERRIDE;
  virtual bool HasConstructionArguments(Sample minimum,
                                        Sample maximum,
                                        size_t bucket_count) const OVERRIDE;
  virtual void Add(Sample value) OVERRIDE;
  virtual scoped_ptr<HistogramSamples> SnapshotSamples() const OVERRIDE;
  virtual void AddSamples(const HistogramSamples& samples) OVERRIDE;
  virtual bool AddSamplesFromPickle(PickleIterator* iter) OVERRIDE;
  virtual void WriteHTMLGraph(std::string* output) const OVERRIDE;
  virtual void WriteAscii(std::string* output) const OVERRIDE;

 protected:
  // |bucket_count| and |ranges| should contain the underflow and overflow
  // buckets. See top comments for example.
  Histogram(const std::string& name,
            Sample minimum,
            Sample maximum,
            size_t bucket_count,
            const BucketRanges* ranges);

  virtual ~Histogram();

  // HistogramBase implementation:
  virtual bool SerializeInfoImpl(Pickle* pickle) const OVERRIDE;

  // Method to override to skip the display of the i'th bucket if it's empty.
  virtual bool PrintEmptyBucket(size_t index) const;

  // Get normalized size, relative to the ranges(i).
  virtual double GetBucketSize(Count current, size_t i) const;

  // Return a string description of what goes in a given bucket.
  // Most commonly this is the numeric value, but in derived classes it may
  // be a name (or string description) given to the bucket.
  virtual const std::string GetAsciiBucketRange(size_t it) const;

 private:
  // Allow tests to corrupt our innards for testing purposes.
  FRIEND_TEST_ALL_PREFIXES(HistogramTest, BoundsTest);
  FRIEND_TEST_ALL_PREFIXES(HistogramTest, BucketPlacementTest);
  FRIEND_TEST_ALL_PREFIXES(HistogramTest, CorruptBucketBounds);
  FRIEND_TEST_ALL_PREFIXES(HistogramTest, CorruptSampleCounts);
  FRIEND_TEST_ALL_PREFIXES(HistogramTest, NameMatchTest);

  friend class StatisticsRecorder;  // To allow it to delete duplicates.
  friend class StatisticsRecorderTest;

  friend BASE_EXPORT_PRIVATE HistogramBase* DeserializeHistogramInfo(
      PickleIterator* iter);
  static HistogramBase* DeserializeInfoImpl(PickleIterator* iter);

  // Implementation of SnapshotSamples function.
  scoped_ptr<SampleVector> SnapshotSampleVector() const;

  //----------------------------------------------------------------------------
  // Helpers for emitting Ascii graphic.  Each method appends data to output.

  void WriteAsciiImpl(bool graph_it,
                      const std::string& newline,
                      std::string* output) const;

  // Find out how large (graphically) the largest bucket will appear to be.
  double GetPeakBucketSize(const SampleVector& samples) const;

  // Write a common header message describing this histogram.
  void WriteAsciiHeader(const SampleVector& samples,
                        Count sample_count,
                        std::string* output) const;

  // Write information about previous, current, and next buckets.
  // Information such as cumulative percentage, etc.
  void WriteAsciiBucketContext(const int64 past, const Count current,
                               const int64 remaining, const size_t i,
                               std::string* output) const;

  // Write textual description of the bucket contents (relative to histogram).
  // Output is the count in the buckets, as well as the percentage.
  void WriteAsciiBucketValue(Count current, double scaled_sum,
                             std::string* output) const;

  // Produce actual graph (set of blank vs non blank char's) for a bucket.
  void WriteAsciiBucketGraph(double current_size, double max_size,
                             std::string* output) const;

  // WriteJSON calls these.
  virtual void GetParameters(DictionaryValue* params) const OVERRIDE;

  virtual void GetCountAndBucketData(Count* count,
                                     ListValue* buckets) const OVERRIDE;

  // Does not own this object. Should get from StatisticsRecorder.
  const BucketRanges* bucket_ranges_;

  Sample declared_min_;  // Less than this goes into counts_[0]
  Sample declared_max_;  // Over this goes into counts_[bucket_count_ - 1].
  size_t bucket_count_;  // Dimension of counts_[].

  // Finally, provide the state that changes with the addition of each new
  // sample.
  scoped_ptr<SampleVector> samples_;

  DISALLOW_COPY_AND_ASSIGN(Histogram);
};

//------------------------------------------------------------------------------

// LinearHistogram is a more traditional histogram, with evenly spaced
// buckets.
class BASE_EXPORT LinearHistogram : public Histogram {
 public:
  virtual ~LinearHistogram();

  /* minimum should start from 1. 0 is as minimum is invalid. 0 is an implicit
     default underflow bucket. */
  static HistogramBase* FactoryGet(const std::string& name,
                                   Sample minimum,
                                   Sample maximum,
                                   size_t bucket_count,
                                   int32 flags);
  static HistogramBase* FactoryTimeGet(const std::string& name,
                                       TimeDelta minimum,
                                       TimeDelta maximum,
                                       size_t bucket_count,
                                       int32 flags);

  struct DescriptionPair {
    Sample sample;
    const char* description;  // Null means end of a list of pairs.
  };

  // Create a LinearHistogram and store a list of number/text values for use in
  // writing the histogram graph.
  // |descriptions| can be NULL, which means no special descriptions to set. If
  // it's not NULL, the last element in the array must has a NULL in its
  // "description" field.
  static HistogramBase* FactoryGetWithRangeDescription(
      const std::string& name,
      Sample minimum,
      Sample maximum,
      size_t bucket_count,
      int32 flags,
      const DescriptionPair descriptions[]);

  static void InitializeBucketRanges(Sample minimum,
                                     Sample maximum,
                                     size_t bucket_count,
                                     BucketRanges* ranges);

  // Overridden from Histogram:
  virtual HistogramType GetHistogramType() const OVERRIDE;

 protected:
  LinearHistogram(const std::string& name,
                  Sample minimum,
                  Sample maximum,
                  size_t bucket_count,
                  const BucketRanges* ranges);

  virtual double GetBucketSize(Count current, size_t i) const OVERRIDE;

  // If we have a description for a bucket, then return that.  Otherwise
  // let parent class provide a (numeric) description.
  virtual const std::string GetAsciiBucketRange(size_t i) const OVERRIDE;

  // Skip printing of name for numeric range if we have a name (and if this is
  // an empty bucket).
  virtual bool PrintEmptyBucket(size_t index) const OVERRIDE;

 private:
  friend BASE_EXPORT_PRIVATE HistogramBase* DeserializeHistogramInfo(
      PickleIterator* iter);
  static HistogramBase* DeserializeInfoImpl(PickleIterator* iter);

  // For some ranges, we store a printable description of a bucket range.
  // If there is no desciption, then GetAsciiBucketRange() uses parent class
  // to provide a description.
  typedef std::map<Sample, std::string> BucketDescriptionMap;
  BucketDescriptionMap bucket_description_;

  DISALLOW_COPY_AND_ASSIGN(LinearHistogram);
};

//------------------------------------------------------------------------------

// BooleanHistogram is a histogram for booleans.
class BASE_EXPORT BooleanHistogram : public LinearHistogram {
 public:
  static HistogramBase* FactoryGet(const std::string& name, int32 flags);

  virtual HistogramType GetHistogramType() const OVERRIDE;

 private:
  BooleanHistogram(const std::string& name, const BucketRanges* ranges);

  friend BASE_EXPORT_PRIVATE HistogramBase* DeserializeHistogramInfo(
      PickleIterator* iter);
  static HistogramBase* DeserializeInfoImpl(PickleIterator* iter);

  DISALLOW_COPY_AND_ASSIGN(BooleanHistogram);
};

//------------------------------------------------------------------------------

// CustomHistogram is a histogram for a set of custom integers.
class BASE_EXPORT CustomHistogram : public Histogram {
 public:
  // |custom_ranges| contains a vector of limits on ranges. Each limit should be
  // > 0 and < kSampleType_MAX. (Currently 0 is still accepted for backward
  // compatibility). The limits can be unordered or contain duplication, but
  // client should not depend on this.
  static HistogramBase* FactoryGet(const std::string& name,
                                   const std::vector<Sample>& custom_ranges,
                                   int32 flags);

  // Overridden from Histogram:
  virtual HistogramType GetHistogramType() const OVERRIDE;

  // Helper method for transforming an array of valid enumeration values
  // to the std::vector<int> expected by HISTOGRAM_CUSTOM_ENUMERATION.
  // This function ensures that a guard bucket exists right after any
  // valid sample value (unless the next higher sample is also a valid value),
  // so that invalid samples never fall into the same bucket as valid samples.
  // TODO(kaiwang): Change name to ArrayToCustomEnumRanges.
  static std::vector<Sample> ArrayToCustomRanges(const Sample* values,
                                                 size_t num_values);
 protected:
  CustomHistogram(const std::string& name,
                  const BucketRanges* ranges);

  // HistogramBase implementation:
  virtual bool SerializeInfoImpl(Pickle* pickle) const OVERRIDE;

  virtual double GetBucketSize(Count current, size_t i) const OVERRIDE;

 private:
  friend BASE_EXPORT_PRIVATE HistogramBase* DeserializeHistogramInfo(
      PickleIterator* iter);
  static HistogramBase* DeserializeInfoImpl(PickleIterator* iter);

  static bool ValidateCustomRanges(const std::vector<Sample>& custom_ranges);
  static BucketRanges* CreateBucketRangesFromCustomRanges(
      const std::vector<Sample>& custom_ranges);

  DISALLOW_COPY_AND_ASSIGN(CustomHistogram);
};

}  // namespace base

#endif  // BASE_METRICS_HISTOGRAM_H_


text:
// ==UserScript==
// @name        Toggl-Button Zendone
// @namespace   https://github.com/jurgenhaas/toggl-button-greasemonkey
// @version     0.9
// @include     https://drupal.org/node/*
// @grant       GM_xmlhttpRequest
// @grant       GM_addStyle
// @grant       GM_getResourceText
// @grant       GM_getValue
// @grant       GM_setValue
// @grant       GM_info
// @grant       GM_registerMenuCommand
// @require     https://greasyfork.org/scripts/2670-toggllibrary/code/TogglLibrary.js
// @resource    togglStyle https://raw.githubusercontent.com/jurgenhaas/toggl-button-greasemonkey/v1.3/TogglLibrary.css
// @description Toggle button for ZenDone
// ==/UserScript==

// @require     http://sizzlemctwizzle.com/423249.js

/*
Not working yet!
TogglButtonGM.init(TogglButtonGM.$newApiUrl, function() {
  TogglButtonGM.render('.actions-table tr', {}, function (elem) {
    console.log('ZENDONE Toggl');
    var description, projectIds = [],
      titleElem = $('.colMain .action-title', elem),
      projectElem = $('.field-name-field-project .field-items .field-item');

    description = titleElem.textContent.trim();
    if (id !== null) {
      description = id + " " + description;
    }

    if (projectElem !== null) {
      projectIds.push(projectElem.textContent.trim());
    }

    TogglButtonGM.createTimerLink({
      className: 'zendone',
      description: description,
      projectIds: projectIds,
      targetSelectors: {
        link: '.colMain .action-title',
        projectSelect: '.colMain .action-title'
      }
    });
  });
});
*/

redpajama_set_name: RedPajamaGithub


text:
import { reducer, initialState, AuthState } from './auth.reducer';
import { Actions } from './auth.actions';

describe('Authentication', () => {
  it('returns initialState by default', () => {
    let state: AuthState = reducer(undefined, { type: 'DO_NOTHING' });
    expect(state).toBe(initialState);
  });
  it('sets loading to true, when starting authentication', () => {
    let state: AuthState = reducer(undefined, Actions.auth());
    expect(state.loading).toBe(true);
  });
});


text:
package v1beta1

type NATSTriggerExpansion interface{}


text:
Restores a versioned S3 bucket to a previous point in time.

## Usage
```bash
AWS_ACCESS_KEY=access AWS_REGION=us-west-2 AWS_SECRET_ACCESS_KEY=secret ./s3-restore --bucket <bucket> --time "2017-10-09 20:58:41 +0000 UTC" restore
```

## AWS Credentials
See the aws docs here for information on advanced credentials configuration
http://docs.aws.amazon.com/sdk-for-go/v1/developer-guide/configuring-sdk.html

## Options
- `--bucket <name>` processes the named bucket
- `--time <time>` accepts any format accepted by https://github.com/araddon/dateparse
- `--endpoint-url <url>` for connecting to third party S3 compatible APIs like EMC ECS
- `--debug` prints debug logging

## Known Issues
- On EMC ECS, the restore will fail with "No Such Version" if you attempt to run it a bucket that was versioned after keys already existed in it. EMC ECS does not support reverting to `null` versionId. This limitation means the bucket you are attempting to restore needs to be versioned from the beginning.  To work around this issue you can copy all of the objects to a new bucket, delete the original bucket, recreate it with versioning on, and move the keys back into the new versioned bucket with the same name as the original.


text:
* Fix parsing of BuildRequires:, Requires:, Conflicts:, Obsoletes:, Provides: with comments at end of line. Thanks [@SuoXC](https://github.com/SuoXC).
* Add CI for Python 3.11.

## 0.12 (2022-07-13)

* Fix %description and %changelog with multi-line strings [#46](https://github.com/bkircher/python-rpm-spec/issues/46). Thanks [@tagoh](https://github.com/tagoh).

## 0.11 (2021-08-05)

Changes:

* Add type annotations for tools like mypy, your IDE, and your brain. Thanks [@KOLANICH](https://github.com/KOLANICH).
* `replace_macros()` function now always expects a Spec instance as second argument. Does not make much sense without.
* Add support for parsing %description and %changelog (see PR [#42](https://github.com/bkircher/python-rpm-spec/pull/42)). Thanks [@BrunoVernay](https://github.com/BrunoVernay).
* Add support for ExcludeArch and ExclusiveArch ([#45](https://github.com/bkircher/python-rpm-spec/pull/45)). Thanks [@tonsh](https://github.com/tonsh).
* Add `warnings_enabled` knob to issue [warnings](https://docs.python.org/3/library/warnings.html#module-warnings) of type `UserWarning` during spec file parsing.

## 0.10 (2020-09-19)

Changes:

* Ignore spaces before ':' separator (see PR [#32][https://github.com/bkircher/python-rpm-spec/pull/32])
* Fix behavior of replace_macro function when macro is a tag, too (see issue [#33](https://github.com/bkircher/python-rpm-spec/issues/33)).

## 0.9 (2020-05-02)

Changes:

* Ignore case when parsing directives

## 0.8 (2018-09-18)

New Features:

* Enable parsing versions in `BuildRequires:` and `Requires:`
* Add support for conditional macros, e.g. `%{?test_macro:expression}`
* Use flit for packaging

## 0.7 (2017-08-10)

New Features:

* Add `Spec.sources_dict` and `Spec.patches_dict`


text:
{-|
Module      : Werewolf.Command.Start
Description : Options and handler for the start subcommand.

Copyright   : (c) Henry J. Wylde, 2016
License     : BSD3
Maintainer  : public@hjwylde.com

Options and handler for the start subcommand.
-}

{-# LANGUAGE FlexibleContexts      #-}
{-# LANGUAGE MultiParamTypeClasses #-}

module Werewolf.Command.Start (
    -- * Options
    Options(..), ExtraRoles(..),

    -- * Handle
    handle,
) where

import Control.Lens.Extra
import Control.Monad.Except
import Control.Monad.Extra
import Control.Monad.Random
import Control.Monad.State
import Control.Monad.Writer

import Data.Text (Text)

import           Game.Werewolf
import           Game.Werewolf.Engine
import           Game.Werewolf.Message.Error
import qualified Game.Werewolf.Variant       as Variant

import System.Random.Shuffle

import Werewolf.System

data Options = Options
    { optExtraRoles :: ExtraRoles
    , optVariant    :: Text
    , argPlayers    :: [Text]
    } deriving (Eq, Show)

data ExtraRoles = None | Random | Use [Text]
    deriving (Eq, Show)

handle :: (MonadIO m, MonadRandom m) => Text -> Text -> Options -> m ()
handle callerName tag (Options extraRoles variant playerNames) = do
    whenM (doesGameExist tag &&^ (hasn't (stage . _GameOver) <$> readGame tag)) $ exitWith failure
        { messages = [gameAlreadyRunningMessage callerName]
        }

    result <- runExceptT $ do
        extraRoles' <- case extraRoles of
            None            -> return []
            Random          -> randomExtraRoles $ length playerNames
            Use roleNames   -> useExtraRoles callerName roleNames

        variant' <- useVariant callerName variant

        let defaultVillagerRole = if is spitefulVillage variant' then spitefulVillagerRole else simpleVillagerRole
        let roles = padRoles extraRoles' (length playerNames + 1) defaultVillagerRole

        players <- createPlayers (callerName:playerNames) <$> shuffleM roles

        runWriterT $ startGame callerName variant' players >>= execStateT checkStage

    case result of
        Left errorMessages      -> exitWith failure { messages = errorMessages }
        Right (game, messages)  -> writeOrDeleteGame tag game >> exitWith success { messages = messages }

randomExtraRoles :: MonadRandom m => Int -> m [Role]
randomExtraRoles n = do
    let minimum = n `div` 4 + 1
    let maximum = n `div` 3 + 1

    count <- getRandomR (minimum, maximum)

    take count <$> shuffleM restrictedRoles

useExtraRoles :: MonadError [Message] m => Text -> [Text] -> m [Role]
useExtraRoles callerName roleNames = forM roleNames $ \roleName -> case findRoleByTag roleName of
    Just role   -> return role
    Nothing     -> throwError [roleDoesNotExistMessage callerName roleName]

findRoleByTag :: Text -> Maybe Role
findRoleByTag tag' = restrictedRoles ^? traverse . filteredBy tag tag'

useVariant :: MonadError [Message] m => Text -> Text -> m Variant
useVariant callerName variantName = case findVariantByTag variantName of
    Just variant   -> return variant
    Nothing         -> throwError [variantDoesNotExistMessage callerName variantName]

findVariantByTag :: Text -> Maybe Variant
findVariantByTag tag' = allVariants ^? traverse . filteredBy Variant.tag tag'

padRoles :: [Role] -> Int -> Role -> [Role]
padRoles roles n defaultVillagerRole = roles ++ villagerRoles ++ simpleWerewolfRoles
    where
        goal                    = 3
        m                       = max (n - length roles) 0
        startingBalance         = sumOf (traverse . balance) roles
        simpleWerewolfBalance   = simpleWerewolfRole ^. balance

        -- Little magic here to calculate how many Werewolves and Villagers we want.
        -- This tries to ensure that the balance of the game is between -3 and 2.
        simpleWerewolvesCount   = (goal - m - startingBalance) `div` (simpleWerewolfBalance - 1) + 1
        villagersCount          = m - simpleWerewolvesCount

        -- N.B., if roles is quite unbalanced then one list will be empty.
        villagerRoles       = replicate villagersCount defaultVillagerRole
        simpleWerewolfRoles = replicate simpleWerewolvesCount simpleWerewolfRole

createPlayers :: [Text] -> [Role] -> [Player]
createPlayers = zipWith newPlayer


text:
from tkinter import *
from random import randint

#返回一个随机的颜色
def getRandomColor():
	color = '#'
	for j in range(6):
		color += toHexChar(randint(0, 15))
	return color

#把十进制的数转化为十六进制的数
def toHexChar(hexValue):
	if hexValue >= 0 and hexValue <= 9:
		return chr(hexValue + ord('0'))
	else:
		return chr(hexValue - 10 + ord('A'))

#
class Ball:
	def __init__(self):
		self.x = 0		#默认的起始位置
		self.y = 0
		self.dx = 2      #运动方向,默认向右
		self.dy = 2
		self.radius = 3		#球的半径
		self.color = getRandomColor()

#
class BounceBalls:
	def __init__(self):
		self.ballList = []

		window = Tk()
		window.title("Bouncing Balls")

		self.width = 350
		self.height = 150
		self.canvas = Canvas(window, bg = "white", width = self.width, height = self.height)
		self.canvas.pack()

		frame = Frame(window)
		frame.pack()

		btStop = Button(frame, text="STOP", command=self.stop)
		btStop.pack(side = LEFT)
		btResume = Button(frame, text="RESUME", command=self.resume)
		btResume.pack(side = LEFT)
		btAdd = Button(frame, text="ADD", command=self.add)
		btAdd.pack(side = LEFT)
		btRemove = Button(frame, text="REMOVE", command=self.remove)
		btRemove.pack(side = LEFT)

		self.sleepTime = 100
		self.isStopped = False
		self.animate()

		window.mainloop()

	def stop(self):
		self.isStopped = True

	def resume(self):
		self.isStopped = False
		self.animate()

	def add(self):
		self.ballList.append(Ball())

	def remove(self):
		self.ballList.pop()

	#球的移动实现
	def animate(self):
		while not self.isStopped:
			self.canvas.after(self.sleepTime)
			self.canvas.update()
			self.canvas.delete("ball")   #与create_oval函数中的tags相对应

			for ball in self.ballList:
				self.redisplayBall(ball)

	#画出球
	def redisplayBall(self, ball):
		#球碰到边界会改方向
		if ball.x > self.width or ball.x < 0:
			ball.dx = -ball.dx
		if ball.y > self.height or ball.y < 0:
			ball.dy = -ball.dy

		ball.x += ball.dx
		ball.y += ball.dy
		self.canvas.create_oval(ball.x-ball.radius, ball.y-ball.radius, ball.x+ball.radius, ball.y+ball.radius, \
			fill = ball.color, tags = "ball")

BounceBalls()


text:
package com.example.android.sunshine.app.data;

import android.provider.BaseColumns;
import android.text.format.Time;

/**
 * Defines table and column names for the weather database.
 */
public class WeatherContract {

    // To make it easy to query for the exact date, we normalize all dates that go into
    // the database to the start of the the Julian day at UTC.
    public static long normalizeDate(long startDate) {
        // normalize the start date to the beginning of the (UTC) day
        Time time = new Time();
        time.set(startDate);
        int julianDay = Time.getJulianDay(startDate, time.gmtoff);
        return time.setJulianDay(julianDay);
    }

    /*
        Inner class that defines the table contents of the location table
        Students: This is where you will add the strings.  (Similar to what has been
        done for WeatherEntry)
     */
    public static final class LocationEntry implements BaseColumns {
        public static final String TABLE_NAME = "location";

        public static final String COLUMN_LOC_SETTING="location_setting";

        public static final String COLUMN_LOC_NAME="city_name";

        public static final String COLUMN_LOC_long="coord_long";

        public static final String COLUMN_LOC_lat="coord_lat";
    }

    /* Inner class that defines the table contents of the weather table */
    public static final class WeatherEntry implements BaseColumns {

        public static final String TABLE_NAME = "weather";

        // Column with the foreign key into the location table.
        public static final String COLUMN_LOC_KEY = "location_id";
        // Date, stored as long in milliseconds since the epoch
        public static final String COLUMN_DATE = "date";
        // Weather id as returned by API, to identify the icon to be used
        public static final String COLUMN_WEATHER_ID = "weather_id";

        // Short description and long description of the weather, as provided by API.
        // e.g "clear" vs "sky is clear".
        public static final String COLUMN_SHORT_DESC = "short_desc";

        // Min and max temperatures for the day (stored as floats)
        public static final String COLUMN_MIN_TEMP = "min";
        public static final String COLUMN_MAX_TEMP = "max";

        // Humidity is stored as a float representing percentage
        public static final String COLUMN_HUMIDITY = "humidity";

        // Humidity is stored as a float representing percentage
        public static final String COLUMN_PRESSURE = "pressure";

        // Windspeed is stored as a float representing windspeed  mph
        public static final String COLUMN_WIND_SPEED = "wind";

        // Degrees are meteorological degrees (e.g, 0 is north, 180 is south).  Stored as floats.
        public static final String COLUMN_DEGREES = "degrees";
    }
}


text:
package com.gamingmesh.jobs.dao;

import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.ArrayList;
import java.util.List;
import java.util.Map.Entry;

import org.bukkit.OfflinePlayer;
import org.bukkit.entity.Player;

import com.gamingmesh.jobs.Jobs;
import com.gamingmesh.jobs.config.ConfigManager;
import com.gamingmesh.jobs.container.Convert;
import com.gamingmesh.jobs.container.Job;
import com.gamingmesh.jobs.container.JobProgression;
import com.gamingmesh.jobs.container.JobsPlayer;
import com.gamingmesh.jobs.container.Log;
import com.gamingmesh.jobs.container.LogAmounts;
import com.gamingmesh.jobs.container.TopList;
import com.gamingmesh.jobs.stuff.Loging;
import com.gamingmesh.jobs.stuff.TimeManage;
import com.gamingmesh.jobs.stuff.UUIDUtil;

/**
 * Data Access Object interface for the Jobs plugin
 *
 * Interface that holds all methods that a DAO needs to have
 * @author Alex
 *
 */
public abstract class JobsDAO {

    private JobsConnectionPool pool;
    private String prefix;

    protected JobsDAO(String driverName, String url, String username, String password, String prefix) {
	this.prefix = prefix;
	try {
	    pool = new JobsConnectionPool(driverName, url, username, password);
	} catch (Exception e) {
	    e.printStackTrace();
	}
    }

    public final synchronized void setUp() throws SQLException {
	setupConfig();
	int version = getSchemaVersion();
	if (version == 0) {
	    Jobs.getPluginLogger().severe("Could not initialize database!  Could not determine schema version!");
	    return;
	}

	try {
	    if (version <= 1)
		checkUpdate1();
	    else if (version <= 2)
		checkUpdate2();

	    checkUpdate4();
	    checkUpdate5();

	    version = 5;
	} finally {
	    updateSchemaVersion(version);
	}
    }

    protected abstract void setupConfig() throws SQLException;

    protected abstract void checkUpdate1() throws SQLException;

    protected abstract void checkUpdate2() throws SQLException;

    protected abstract void checkUpdate4() throws SQLException;

    protected abstract void checkUpdate5() throws SQLException;

    /**
     * Gets the database prefix
     * @return the prefix
     */
    protected String getPrefix() {
	return prefix;
    }

    /**
     * Get all jobs the player is part of.
     * @param playerUUID - the player being searched for
     * @return list of all of the names of the jobs the players are part of.
     */
    public synchronized List<JobsDAOData> getAllJobs(OfflinePlayer player) {
	ArrayList<JobsDAOData> jobs = new ArrayList<JobsDAOData>();
	JobsConnection conn = getConnection();
	if (conn == null)
	    return jobs;
	try {
	    PreparedStatement prest = conn.prepareStatement("SELECT `player_uuid`, `job`, `level`, `experience` FROM `" + prefix + "jobs` WHERE `player_uuid` = ?;");
	    prest.setBytes(1, UUIDUtil.toBytes(player.getUniqueId()));
	    ResultSet res = prest.executeQuery();
	    while (res.next()) {
		jobs.add(new JobsDAOData(player.getUniqueId(), res.getString(2), res.getInt(3), res.getInt(4)));
	    }
	    prest.close();
	} catch (SQLException e) {
	    e.printStackTrace();
	}
	return jobs;
    }

    /**
     * Get player count for a job.
     * @param JobName - the job name
     * @return amount of player currently working.
     */
    public synchronized int getTotalPlayerAmountByJobName(String JobName) {
	JobsConnection conn = getConnection();
	if (conn == null)
	    return 0;
	int count = 0;
	try {
	    PreparedStatement prest = conn.prepareStatement("SELECT COUNT(*) FROM `" + prefix + "jobs` WHERE `job` = ?;");
	    prest.setString(1, JobName);
	    ResultSet res = prest.executeQuery();
	    while (res.next()) {
		count = res.getInt(1);
	    }
	    prest.close();
	} catch (SQLException e) {
	    e.printStackTrace();
	}
	return count;
    }

    /**
     * Get player count for a job.
     * @return total amount of player currently working.
     */
    public synchronized int getTotalPlayers() {
	JobsConnection conn = getConnection();
	if (conn == null)
	    return 0;
	int count = 0;
	try {
	    PreparedStatement prest = conn.prepareStatement("SELECT COUNT(*) FROM `" + prefix + "jobs`;");
	    ResultSet res = prest.executeQuery();
	    while (res.next()) {
		count = res.getInt(1);
	    }
	    prest.close();
	} catch (SQLException e) {
	    e.printStackTrace();
	}
	return count;
    }

    /**
     * Get all jobs the player is part of.
     * @param userName - the player being searched for
     * @return list of all of the names of the jobs the players are part of.
     */
    public synchronized List<JobsDAOData> getAllJobsOffline(String userName) {
	ArrayList<JobsDAOData> jobs = new ArrayList<JobsDAOData>();
	JobsConnection conn = getConnection();
	if (conn == null)
	    return jobs;
	try {
	    PreparedStatement prest = conn.prepareStatement("SELECT `player_uuid`, `job`, `level`, `experience` FROM `" + prefix + "jobs` WHERE `username` LIKE ?;");
	    prest.setString(1, userName);
	    ResultSet res = prest.executeQuery();
	    while (res.next()) {
		jobs.add(new JobsDAOData(UUIDUtil.fromBytes(res.getBytes(1)), res.getString(2), res.getInt(3), res.getInt(4)));
	    }
	    prest.close();
	} catch (SQLException e) {
	    e.printStackTrace();
	}
	return jobs;
    }

    /**
     * Join a job (create player-job entry from storage)
     * @param player - player that wishes to join the job
     * @param job - job that the player wishes to join
     */
    public synchronized void joinJob(JobsPlayer jPlayer, Job job) {
	JobsConnection conn = getConnection();
	if (conn == null)
	    return;
	try {
	    int level = 1;
	    int exp = 0;
	    if (checkArchive(jPlayer, job).size() > 0) {
		List<Integer> info = checkArchive(jPlayer, job);
		level = info.get(0);
		deleteArchive(jPlayer, job);
	    }
	    PreparedStatement prest = conn.prepareStatement("INSERT INTO `" + prefix
		+ "jobs` (`player_uuid`, `username`, `job`, `level`, `experience`) VALUES (?, ?, ?, ?, ?);");
	    prest.setBytes(1, UUIDUtil.toBytes(jPlayer.getPlayerUUID()));
	    prest.setString(2, jPlayer.getUserName());
	    prest.setString(3, job.getName());
	    prest.setInt(4, level);
	    prest.setInt(5, exp);
	    prest.execute();
	    prest.close();
	} catch (SQLException e) {
	    e.printStackTrace();
	}
    }

    /**
     * Join a job (create player-job entry from storage)
     * @param player - player that wishes to join the job
     * @param job - job that the player wishes to join
     * @throws SQLException
     */
    public List<Convert> convertDatabase(Player Player, String table) throws SQLException {
	JobsConnection conn = getConnection();
	if (conn == null)
	    return null;

	List<Convert> list = new ArrayList<Convert>();
	try {
	    PreparedStatement prest = conn.prepareStatement("SELECT * FROM `" + prefix + table + "`");
	    ResultSet res = prest.executeQuery();
	    while (res.next()) {
		list.add(new Convert(res.getInt("id"), res.getString("username"), UUIDUtil.fromBytes(res.getBytes("player_uuid")), res.getString("job"), res.getInt(
		    "level"), res.getInt("experience")));
	    }
	    prest.close();
	} catch (SQLException e) {
	    e.printStackTrace();
	}

	try {
	    conn.closeConnection();
	} catch (SQLException e) {
	    e.printStackTrace();
	}
	return list;
    }

    public void continueConvertions(List<Convert> list, String table) throws SQLException {
	JobsConnection conns = this.getConnection();
	if (conns == null)
	    return;
	PreparedStatement insert = null;
	int i = list.size();
	try {

	    Statement statement = conns.createStatement();
	    if (ConfigManager.getJobsConfiguration().storageMethod.equalsIgnoreCase("sqlite")) {
		statement.executeUpdate("TRUNCATE `" + getPrefix() + table + "`");
	    } else {
		statement.executeUpdate("DELETE from `" + getPrefix() + table + "`");
	    }

	    insert = conns.prepareStatement("INSERT INTO `" + getPrefix() + table + "` (`username`,`player_uuid`, `job`, `level`, `experience`) VALUES (?, ?, ?, ?, ?);");
	    conns.setAutoCommit(false);
	    while (i > 0) {
		i--;
		Convert convertData = list.get(i);
		insert.setString(1, convertData.GetName());
		insert.setBytes(2, UUIDUtil.toBytes(convertData.GetUuid()));
		insert.setString(3, convertData.GetJobName());
		insert.setInt(4, convertData.GetLevel());
		insert.setInt(5, convertData.GetExp());
		insert.addBatch();
	    }
	    insert.executeBatch();
	    conns.commit();
	    conns.setAutoCommit(true);
	} finally {
	    if (insert != null) {
		try {
		    insert.close();
		} catch (SQLException e) {
		}
	    }
	}
    }

    /**
     * Quit a job (delete player-job entry from storage)
     * @param player - player that wishes to quit the job
     * @param job - job that the player wishes to quit
     */
    public synchronized void quitJob(JobsPlayer jPlayer, Job job) {
	JobsConnection conn = getConnection();
	if (conn == null)
	    return;
	try {
	    PreparedStatement prest = conn.prepareStatement("DELETE FROM `" + prefix + "jobs` WHERE `player_uuid` = ? AND `job` = ?;");
	    prest.setBytes(1, UUIDUtil.toBytes(jPlayer.getPlayerUUID()));
	    prest.setString(2, job.getName());
	    prest.execute();
	    prest.close();
	} catch (SQLException e) {
	    e.printStackTrace();
	}
    }

    /**
     * Record job to archive
     * @param player - player that wishes to quit the job
     * @param job - job that the player wishes to quit
     */
    public void recordToArchive(JobsPlayer jPlayer, Job job) {
	JobsConnection conn = getConnection();
	if (conn == null)
	    return;
	try {
	    int level = 1;
	    int exp = 0;
	    for (JobProgression progression : jPlayer.getJobProgression()) {
		if (progression.getJob().getName().equalsIgnoreCase(job.getName())) {
		    level = progression.getLevel();
		    exp = (int) progression.getExperience();
		}
	    }
	    PreparedStatement prest = conn.prepareStatement("INSERT INTO `" + prefix
		+ "archive` (`player_uuid`, `username`, `job`, `level`, `experience`) VALUES (?, ?, ?, ?, ?);");
	    prest.setBytes(1, UUIDUtil.toBytes(jPlayer.getPlayerUUID()));
	    prest.setString(2, jPlayer.getUserName());
	    prest.setString(3, job.getName());
	    prest.setInt(4, level);
	    prest.setInt(5, exp);
	    prest.execute();
	    prest.close();
	} catch (SQLException e) {
	    e.printStackTrace();
	}
    }

    /**
     * Check job in archive
     * @param player - player that wishes to quit the job
     * @param job - job that the player wishes to quit
     */
    public synchronized List<Integer> checkArchive(JobsPlayer jPlayer, Job job) {
	JobsConnection conn = getConnection();
	if (conn == null)
	    return null;
	try {
	    List<Integer> info = new ArrayList<Integer>();
	    PreparedStatement prest = conn.prepareStatement("SELECT `level`, `experience` FROM `" + prefix + "archive` WHERE `player_uuid` = ? AND `job` = ?;");
	    prest.setBytes(1, UUIDUtil.toBytes(jPlayer.getPlayerUUID()));
	    prest.setString(2, job.getName());
	    ResultSet res = prest.executeQuery();
	    if (res.next()) {
		int level = (int) ((res.getInt(1) - (res.getInt(1) * (ConfigManager.getJobsConfiguration().levelLossPercentage / 100.0))));
		if (level < 1)
		    level = 1;

		int maxLevel = 0;
		if (jPlayer.havePermission("jobs." + job.getName() + ".vipmaxlevel") && job.getVipMaxLevel() != 0)
		    maxLevel = job.getVipMaxLevel();
		else
		    maxLevel = job.getMaxLevel();

		if (ConfigManager.getJobsConfiguration().fixAtMaxLevel && res.getInt(1) == maxLevel)
		    level = res.getInt(1);
		info.add(level);
		info.add(res.getInt(2));
	    }
	    prest.close();
	    return info;
	} catch (SQLException e) {
	    e.printStackTrace();
	}
	return null;
    }

    public List<TopList> getGlobalTopList() {
	return getGlobalTopList(0);
    }

    /**
     * Get all jobs from archive by player
     * @param player - targeted player
     * @return info - information about jobs
     */
    public List<TopList> getGlobalTopList(int start) {
	JobsConnection conn = getConnection();

	List<TopList> names = new ArrayList<TopList>();

	if (conn == null)
	    return null;
	try {

	    PreparedStatement prest = conn.prepareStatement("SELECT username, player_uuid, COUNT(*) AS amount,  sum(level) AS totallvl FROM `" + prefix
		+ "jobs` GROUP BY username ORDER BY totallvl DESC LIMIT " + start + ",20;");
	    ResultSet res = prest.executeQuery();

	    while (res.next()) {

		TopList top = new TopList(res.getString("username"), res.getInt("totallvl"), 0, res.getBytes("player_uuid"));

		names.add(top);
	    }

	    prest.close();
	    return names;
	} catch (SQLException e) {
	    e.printStackTrace();
	}
	return names;
    }

    /**
     * Get all jobs from archive by player
     * @param player - targeted player
     * @return info - information about jobs
     */
    public synchronized List<String> getJobsFromArchive(JobsPlayer jPlayer) {
	JobsConnection conn = getConnection();
	if (conn == null)
	    return null;
	try {
	    List<String> info = new ArrayList<String>();
	    PreparedStatement prest = conn.prepareStatement("SELECT `job`, `level`, `experience`  FROM `" + prefix + "archive` WHERE `player_uuid` = ?;");
	    prest.setBytes(1, UUIDUtil.toBytes(jPlayer.getPlayerUUID()));
	    ResultSet res = prest.executeQuery();
	    while (res.next()) {

		int level = (int) ((res.getInt(2) - (res.getInt(2) * (ConfigManager.getJobsConfiguration().levelLossPercentage / 100.0))));
		if (level < 1)
		    level = 1;

		int maxLevel = 0;
		if (jPlayer.havePermission("jobs." + Jobs.getJob(res.getString(1)).getName() + ".vipmaxlevel"))
		    maxLevel = Jobs.getJob(res.getString(1)).getVipMaxLevel();
		else
		    maxLevel = Jobs.getJob(res.getString(1)).getMaxLevel();

		if (ConfigManager.getJobsConfiguration().fixAtMaxLevel && res.getInt(2) == maxLevel)
		    level = res.getInt(2);

		info.add(res.getString(1) + ":" + res.getInt(2) + ":" + level + ":" + res.getInt(3));
	    }
	    prest.close();
	    return info;
	} catch (SQLException e) {
	    e.printStackTrace();
	}
	return null;
    }

    /**
     * Delete job from archive
     * @param player - player that wishes to quit the job
     * @param job - job that the player wishes to quit
     */
    public synchronized void deleteArchive(JobsPlayer jPlayer, Job job) {
	JobsConnection conn = getConnection();
	if (conn == null)
	    return;
	try {
	    PreparedStatement prest = conn.prepareStatement("DELETE FROM `" + prefix + "archive` WHERE `player_uuid` = ? AND `job` = ?;");
	    prest.setBytes(1, UUIDUtil.toBytes(jPlayer.getPlayerUUID()));
	    prest.setString(2, job.getName());
	    prest.execute();
	    prest.close();
	} catch (SQLException e) {
	    e.printStackTrace();
	}
    }

    /**
     * Save player-job information
     * @param jobInfo - the information getting saved
     */
    public synchronized void save(JobsPlayer player) {
	JobsConnection conn = getConnection();
	if (conn == null)
	    return;
	try {
	    PreparedStatement prest = conn.prepareStatement("UPDATE `" + prefix + "jobs` SET `level` = ?, `experience` = ? WHERE `player_uuid` = ? AND `job` = ?;");
	    for (JobProgression progression : player.getJobProgression()) {
		prest.setInt(1, progression.getLevel());
		prest.setInt(2, (int) progression.getExperience());
		prest.setBytes(3, UUIDUtil.toBytes(player.getPlayerUUID()));
		prest.setString(4, progression.getJob().getName());
		prest.execute();
	    }
	    prest.close();
	} catch (SQLException e) {
	    e.printStackTrace();
	}
    }

    /**
     * Save player-job information
     * @param jobInfo - the information getting saved
     */
    public synchronized void saveLog(JobsPlayer player) {
	JobsConnection conn = getConnection();
	if (conn == null)
	    return;
	try {

	    PreparedStatement prest = conn.prepareStatement("UPDATE `" + prefix
		+ "log` SET `count` = ?, `money` = ?, `exp` = ? WHERE `player_uuid` = ? AND `time` = ? AND `action` = ? AND `itemname` = ?;");
	    for (Log log : player.getLog()) {
		for (Entry<String, LogAmounts> one : log.getAmountList().entrySet()) {
		    if (one.getValue().isNewEntry())
			continue;

		    prest.setInt(1, one.getValue().getCount());
		    prest.setDouble(2, one.getValue().getMoney());
		    prest.setDouble(3, one.getValue().getExp());

		    prest.setBytes(4, UUIDUtil.toBytes(player.getPlayerUUID()));
		    prest.setInt(5, log.getDate());
		    prest.setString(6, log.getActionType());
		    prest.setString(7, one.getKey());
		    prest.execute();
		}
	    }
	    prest = conn.prepareStatement("INSERT INTO `" + prefix
		+ "log` (`player_uuid`, `username`, `time`, `action`, `itemname`, `count`, `money`, `exp`) VALUES (?, ?, ?, ?, ?, ?, ?, ?);");
	    for (Log log : player.getLog()) {
		for (Entry<String, LogAmounts> one : log.getAmountList().entrySet()) {

		    if (!one.getValue().isNewEntry())
			continue;

		    one.getValue().setNewEntry(false);

		    prest.setBytes(1, UUIDUtil.toBytes(player.getPlayerUUID()));
		    prest.setString(2, player.getUserName());
		    prest.setInt(3, log.getDate());
		    prest.setString(4, log.getActionType());
		    prest.setString(5, one.getKey());
		    prest.setInt(6, one.getValue().getCount());
		    prest.setDouble(7, one.getValue().getMoney());
		    prest.setDouble(8, one.getValue().getExp());
		    prest.execute();
		}
	    }
	    prest.close();
	} catch (SQLException e) {
	    e.printStackTrace();
	}
    }

    /**
     * Save player-job information
     * @param jobInfo - the information getting saved
     */
    public void loadLog(JobsPlayer player) {
	JobsConnection conn = getConnection();
	if (conn == null)
	    return;
	try {

	    int time = TimeManage.timeInInt();

	    PreparedStatement prest = conn.prepareStatement("SELECT `player_uuid`, `username`, `time`, `action`, `itemname`, `count`, `money`, `exp` FROM `" + prefix
		+ "log` WHERE `player_uuid` = ?  AND `time` = ? ;");
	    prest.setBytes(1, UUIDUtil.toBytes(player.getPlayerUUID()));
	    prest.setInt(2, time);
	    ResultSet res = prest.executeQuery();
	    while (res.next()) {
		Loging.loadToLog(player, res.getString("action"), res.getString("itemname"), res.getInt("count"), res.getDouble("money"), res.getDouble("exp"));
	    }
	    res.close();
	    prest.close();
	} catch (SQLException e) {
	    e.printStackTrace();
	}
    }

    /**
     * Save player-job information
     * @param jobInfo - the information getting saved
     * @return
     */
    public List<String> getLognameList(int fromtime, int untiltime) {
	JobsConnection conn = getConnection();
	if (conn == null)
	    return null;
	try {
	    List<String> nameList = new ArrayList<String>();

	    PreparedStatement prest = conn.prepareStatement("SELECT `username` FROM `" + prefix
		+ "log` WHERE `time` >= ?  AND `time` <= ? ;");
	    prest.setInt(1, fromtime);
	    prest.setInt(2, untiltime);
	    ResultSet res = prest.executeQuery();
	    while (res.next()) {
		if (!nameList.contains(res.getString("username")))
		    nameList.add(res.getString("username"));
	    }
	    res.close();
	    prest.close();
	    return nameList;
	} catch (SQLException e) {
	    e.printStackTrace();
	}
	return null;
    }

    /**
     * Show top list
     * @param toplist - toplist by jobs name
     * @return
     */
    public synchronized ArrayList<TopList> toplist(String jobsname, int limit) {
	ArrayList<TopList> jobs = new ArrayList<TopList>();
	JobsConnection conn = getConnection();
	if (conn == null)
	    return jobs;
	try {
	    PreparedStatement prest = conn.prepareStatement("SELECT `username`, `level`, `experience`,`player_uuid` FROM `" + prefix
		+ "jobs` WHERE `job` LIKE ? ORDER BY `level` DESC, LOWER(username) ASC LIMIT " + limit + ", 15;");
	    prest.setString(1, jobsname);
	    ResultSet res = prest.executeQuery();
	    while (res.next()) {
		jobs.add(new TopList(res.getString(1), res.getInt(2), res.getInt(3), res.getBytes(4)));
	    }
	    prest.close();
	} catch (SQLException e) {
	    e.printStackTrace();
	}
	return jobs;
    }

    /**
     * Get the number of players that have a particular job
     * @param job - the job
     * @return  the number of players that have a particular job
     */
    public synchronized int getSlotsTaken(Job job) {
	int slot = 0;
	JobsConnection conn = getConnection();
	if (conn == null)
	    return slot;
	try {
	    PreparedStatement prest = conn.prepareStatement("SELECT COUNT(*) FROM `" + prefix + "jobs` WHERE `job` = ?;");
	    prest.setString(1, job.getName());
	    ResultSet res = prest.executeQuery();
	    if (res.next()) {
		slot = res.getInt(1);
	    }
	    prest.close();
	} catch (SQLException e) {
	    e.printStackTrace();
	}
	return slot;
    }

    /**
     * Gets the current schema version
     * @return schema version number
     */
    protected int getSchemaVersion() {
	JobsConnection conn = getConnection();
	if (conn == null)
	    return 0;
	PreparedStatement prest = null;
	try {
	    prest = conn.prepareStatement("SELECT `value` FROM `" + prefix + "config` WHERE `key` = ?;");
	    prest.setString(1, "version");
	    ResultSet res = prest.executeQuery();
	    if (res.next()) {
		return Integer.valueOf(res.getString(1));
	    }
	} catch (SQLException e) {
	    e.printStackTrace();
	} catch (NumberFormatException e) {
	    e.printStackTrace();
	} finally {
	    if (prest != null) {
		try {
		    prest.close();
		} catch (SQLException e) {
		}
	    }
	}

	return 0;
    }

    /**
     * Updates schema to version number
     * @param version
     */
    protected void updateSchemaVersion(int version) {
	updateSchemaConfig("version", Integer.toString(version));
    }

    /**
     * Updates configuration value
     * @param key - the configuration key
     * @param value - the configuration value
     */
    private void updateSchemaConfig(String key, String value) {
	JobsConnection conn = getConnection();
	if (conn == null)
	    return;
	PreparedStatement prest = null;
	try {
	    prest = conn.prepareStatement("UPDATE `" + prefix + "config` SET `value` = ? WHERE `key` = ?;");
	    prest.setString(1, value);
	    prest.setString(2, key);
	    prest.execute();
	} catch (SQLException e) {
	    e.printStackTrace();
	} finally {
	    if (prest != null) {
		try {
		    prest.close();
		} catch (SQLException e) {
		}
	    }
	}
    }

    /**
     * Executes an SQL query
     * @param sql - The SQL
     * @throws SQLException
     */
    public void executeSQL(String sql) throws SQLException {
	JobsConnection conn = getConnection();
	Statement stmt = conn.createStatement();
	try {
	    stmt.execute(sql);
	} finally {
	    try {
		stmt.close();
	    } catch (SQLException e) {
	    }
	}
    }

    /**
     * Get a database connection
     * @return  JobsConnection object
     * @throws SQLException
     */
    protected JobsConnection getConnection() {
	try {
	    return pool.getConnection();
	} catch (SQLException e) {
	    Jobs.getPluginLogger().severe("Unable to connect to the database: " + e.getMessage());
	    return null;
	}
    }

    /**
     * Close all active database handles
     */
    public synchronized void closeConnections() {
	pool.closeConnection();
    }
}


text:
require 'mail/fields/named_structured_field'

module Mail
  # keywords        =       "Keywords:" phrase *("," phrase) CRLF
  class KeywordsField < NamedStructuredField #:nodoc:
    NAME = 'Keywords'

    def element
      @element ||= PhraseList.new(value)
    end

    def keywords
      element.phrases
    end

    def default
      keywords
    end

    private
      def do_decode
        keywords.join(', ')
      end

      def do_encode
        "#{name}: #{keywords.join(",\r\n ")}\r\n"
      end
  end
end


text:
-	[`6.0.3`, `6.0` (*6.0/Dockerfile*)](https://github.com/Lightstreamer/Docker/blob/5cb379d682574ad2170166d93306124c633a644f/6.0/Dockerfile)
-	[`6.1.0`, `6.1`, `6`, `latest` (*6.1/Dockerfile*)](https://github.com/Lightstreamer/Docker/blob/94415d471c10c4e64ca1bae2d753cbe94fd5fa61/6.1/Dockerfile)

For more information about this image and its history, please see [the relevant manifest file (`library/lightstreamer`)](https://github.com/docker-library/official-images/blob/master/library/lightstreamer). This image is updated via [pull requests to the `docker-library/official-images` GitHub repo](https://github.com/docker-library/official-images/pulls?q=label%3Alibrary%2Flightstreamer).

For detailed information about the virtual/transfer sizes and individual layers of each of the above supported tags, please see [the `repos/lightstreamer/tag-details.md` file](https://github.com/docker-library/repo-info/blob/master/repos/lightstreamer/tag-details.md) in [the `docker-library/repo-info` GitHub repo](https://github.com/docker-library/repo-info).

# What is Lightstreamer Server?

Lightstreamer is a real-time messaging server optimized for the Internet. Blending WebSockets, HTTP, and push notifications, it streams data to/from mobile, tablet, browser-based, desktop, and IoT applications.

For more information and related downloads for Lightstreamer Server and other Lightstreaner products, please visit [www.lightstreamer.com](http://www.lightstreamer.com).

![logo](https://raw.githubusercontent.com/docker-library/docs/3a58248e2d43ced58c294b7980b55846a0ddc9e5/lightstreamer/logo.png)

# How to use this image

## Up and Running

Launch the container with the default configuration:

```console
$ docker run --name ls-server -d -p 80:8080 lightstreamer
```

This will map port 8080 inside the container to port 80 on local host. Then point your browser to `http://localhost` and watch the Welcome page showing real time data flowing in from the locally deployed demo application, which is a first overview of the unique features offered by the Lightstreamer technology. More examples are available online at the [demo site](http://demos.lightstreamer.com).

## Custom settings

It is possibile to customize each aspect of the Lightstreamer instance running into the container. For example, a specific configuration file may be supplied as follows:

```console
$ docker run --name ls-server -v /path/to/my-lightstreamer_conf.xml:/lightstreamer/conf/lightstreamer_conf.xml -d -p 80:8080 lightstreamer
```

In the same way, you could provide a custom logging configuration, maybe in this case also specifying a dedicated volume to ensure both the persistence of log files and better performance of the container:

```console
$ docker run --name ls-server -v /path/to/my-lightstreamer_log_conf.xml:/lightstreamer/conf/lightstreamer_log_conf.xml -v /path/to/logs:/lightstreamer/logs -d -p 80:8080 lightstreamer
```

If you also change in your `my-lightstreamer_log_conf.xml` file the default logging path from `../logs` to `/path/to/dest/logs`:

```console
$ docker run --name ls-server -v /path/to/my-lightstreamer_log_conf.xml:/lightstreamer/conf/lightstreamer_log_conf.xml -v /path/to/hosted/logs:/path/to/dest/logs -d -p 80:8080 lightstreamer
```

Alternatively, the above tasks can be executed by deriving a new image through a `Dockerfile` as the following:

```dockerfile
FROM lightstreamer

# Please specify a COPY command only for the the required custom configuration file
COPY my-lightstreamer_conf.xml /lightstreamer/conf/lightstreamer_conf.xml
COPY my-lightstreamer_log_conf.xml /lightstreamer/conf/lightstreamer_log_conf.xml
```

where `my-lightstreamer_conf.xml` and `my-lightstreamer_log_conf.xml` are your custom configuration files, placed in the same directory as the Dockerfile. By simply running the command:

```console
$ docker build -t my-lightstreamer .
```

the new image will be built along with the provided files. After that, launch the container:

```console
$ docker run --name ls-server -d -p 80:8080 my-lightstreamer
```

To get more detailed information on how to configure the Lightstreamer server, please see the inline documentation in the `lighstreamer_conf.xml` and `lighstreamer_log_conf.xml` files you can find under the `conf` folder of the installation directory.

## Deployment of Adapter Sets

You might want to use this image even with any Adapter Set, either developed by yourself or provided by third parties.

To accomplish such goal, you may use similar strategies to those illustrated above:

### Deployment of a single Adapter Set

To deploy a single custom Adapter Set, the simplest way is to attach its files into the factory adapters folder, as follows:

```console
$ docker run --name ls-server -v /path/to/my-adapter-set:/lightstreamer/adapters/my-adapter-set -d -p 80:8080 lightstreamer
```

### Full replacement of the "adapters" folder

In the case you have many custom Adapter Sets to deploy, a more appropriate strategy is to replace the factory adapters folder with the one located in your host machine:

```console
$ docker run --name ls-server -v /path/to/my-adapters:/lightstreamer/adapters -d -p 80:8080 lightstreamer
```

In this case, the `/path/to/my-adapters` folder has to be structured with the required layout for an adapters folder:

```console
/path/to/my-adapters+
                    +my_adapter_set_1
                    +my_adapter_set_2
                    ...
                    +my_adapter_set_N

```

### Building a new image

Once again, a linear and clean approach is to make a new image including all needed files.

In this case, you could write a simple Docker file in which the list of all your Adapter Sets configuration files is provided:

```dockerfile
FROM lightstreamer

# Will copy the contents of N Adapter Sets into the factory adapters folder
COPY my-adapter-set-1 /lightstreamer/adapters/my-adapter-set-1
COPY my-adapter-set-2 /lightstreamer/adapters/my-adapter-set-2
COPY my-adapter-set-3 /lightstreamer/adapters/my-adapter-set-3
```

Then, just build and start the container as already explained.

## Deployment of web server pages

There might be some circumstances where you would like provide custom pages for the internal web server of the Lightstreamer Server. Even in this case, it is possible to customize the container by employing the same techniques as above.

For example, with the following command you will be able to fully replace the factory `pages` folder:

```console
$ docker run --name ls-server -v /path/to/custom/pages:/lightstreamer/pages -d -p 80:8080 lightstreamer
```

where `/path/to/custom/pages` is the path in your host machine containing the replacing web content files.

# License

View [license information](http://www.lightstreamer.com/lightstreamer-sla) for the software contained in this image.

# Supported Docker versions

This image is officially supported on Docker version 1.13.0.

Support for older versions (down to 1.6) is provided on a best-effort basis.

Please see [the Docker installation documentation](https://docs.docker.com/installation/) for details on how to upgrade your Docker daemon.

# User Feedback

## Issues

If you have any problems with or questions about this image, please contact us through a [GitHub issue](https://github.com/Lightstreamer/Docker/issues). If the issue is related to a CVE, please check for [a `cve-tracker` issue on the `official-images` repository first](https://github.com/docker-library/official-images/issues?q=label%3Acve-tracker).

You can also reach many of the official image maintainers via the `#docker-library` IRC channel on [Freenode](https://freenode.net).

## Contributing

You are invited to contribute new features, fixes, or updates, large or small; we are always thrilled to receive pull requests, and do our best to process them as fast as we can.

Before you start to code, we recommend discussing your plans through a [GitHub issue](https://github.com/Lightstreamer/Docker/issues), especially for more ambitious contributions. This gives other contributors a chance to point you in the right direction, give you feedback on your design, and help you find out if someone else is working on the same thing.

## Documentation

Documentation for this image is stored in the [`lightstreamer/` directory](https://github.com/docker-library/docs/tree/master/lightstreamer) of the [`docker-library/docs` GitHub repo](https://github.com/docker-library/docs). Be sure to familiarize yourself with the [repository's `README.md` file](https://github.com/docker-library/docs/blob/master/README.md) before attempting a pull request.


text:
<?php

namespace OCA\DAV\CardDAV;

use OCA\DAV\CardDAV\Xml\Groups;
use Sabre\DAV\INode;
use Sabre\DAV\PropFind;
use Sabre\DAV\Server;

class Plugin extends \Sabre\CardDAV\Plugin {
	public function initialize(Server $server) {
		$server->on('propFind', [$this, 'propFind']);
		parent::initialize($server);
	}

	/**
	 * Returns the addressbook home for a given principal
	 *
	 * @param string $principal
	 * @return string
	 */
	protected function getAddressbookHomeForPrincipal($principal) {
		if (\strrpos($principal, 'principals/users', -\strlen($principal)) !== false) {
			list(, $principalId) = \Sabre\Uri\split($principal);
			return self::ADDRESSBOOK_ROOT . '/users/' . $principalId;
		}
		if (\strrpos($principal, 'principals/groups', -\strlen($principal)) !== false) {
			list(, $principalId) = \Sabre\Uri\split($principal);
			return self::ADDRESSBOOK_ROOT . '/groups/' . $principalId;
		}
		if (\strrpos($principal, 'principals/system', -\strlen($principal)) !== false) {
			list(, $principalId) = \Sabre\Uri\split($principal);
			return self::ADDRESSBOOK_ROOT . '/system/' . $principalId;
		}

		throw new \LogicException('This is not supposed to happen');
	}

	/**
	 * Adds all CardDAV-specific properties
	 *
	 * @param PropFind $propFind
	 * @param INode $node
	 * @return void
	 */
	public function propFind(PropFind $propFind, INode $node) {
		$ns = '{http://owncloud.org/ns}';

		if ($node instanceof AddressBook) {
			$propFind->handle($ns . 'groups', function () use ($node) {
				return new Groups($node->getContactsGroups());
			});
		}
	}
}


text:
namespace Corlib.IO {
    public enum FileSystemChangeType : byte {
        None,
        Created,
        Renamed,
        Changed,
        Deleted,
        Exception
    }
}


text:
ISTIO_VERSION="${ISTIO_VERSION:-1.15.1}"
curl -L https://istio.io/downloadIstio | ISTIO_VERSION=$ISTIO_VERSION sh -
cd istio-$ISTIO_VERSION
export PATH=$PWD/bin:$PATH
istioctl install --set profile=demo -y


text:
package iec61499

import (
	"fmt"
	"reflect"
)

//d is used to overwrite existing debug info when testing for equality (line numbers/source file names don't matter when testing equality)
var d = DebugInfo{}

//FBsEqual checks two function blocks for equality.
//It only checks the important fields.
func FBsEqual(a FB, b FB) bool {
	if a.Name != b.Name {
		return false
	}

	if a.Identification.Standard != b.Identification.Standard {
		return false
	}

	if same := blockInterfacesSame(a, b); same != true {
		return false
	}

	if a.BasicFB != nil && b.BasicFB != nil {
		return basicFbsSame(*a.BasicFB, *b.BasicFB)
	}

	if a.CompositeFB != nil && b.CompositeFB != nil {
		return compositeFbsSame(*a.CompositeFB, *b.CompositeFB)
	}

	if a.ServiceFB != nil && b.ServiceFB != nil {
		return siFbsSame(*a.ServiceFB, *b.ServiceFB)
	}

	if a.HybridFB != nil && b.HybridFB != nil {
		fmt.Printf("I don't know how to test hybridfb equivalence")
		return false
	}

	return false //don't know how to test equivalents on other types of block
}

func blockInterfacesSame(a FB, b FB) bool {
	if len(a.EventInputs) != len(b.EventInputs) {
		return false
	}
	for i := 0; i < len(a.EventInputs); i++ {
		if a.EventInputs[i].Name != b.EventInputs[i].Name {
			return false
		}
	}

	if len(a.EventOutputs) != len(b.EventOutputs) {
		return false
	}
	for i := 0; i < len(a.EventOutputs); i++ {
		if a.EventOutputs[i].Name != b.EventOutputs[i].Name {
			return false
		}
	}

	if len(a.InputVars) != len(b.InputVars) {
		return false
	}
	for i := 0; i < len(a.InputVars); i++ {
		a.InputVars[i].DebugInfo = d
		b.InputVars[i].DebugInfo = d
		if a.InputVars[i] != b.InputVars[i] {
			return false
		}
	}

	if len(a.OutputVars) != len(b.OutputVars) {
		return false
	}
	for i := 0; i < len(a.OutputVars); i++ {
		a.OutputVars[i].DebugInfo = d
		b.OutputVars[i].DebugInfo = d
		if a.OutputVars[i] != b.OutputVars[i] {
			return false
		}
	}

	return true
}

func basicFbsSame(a BasicFB, b BasicFB) bool {
	if len(a.Algorithms) != len(b.Algorithms) {
		return false
	}
	for i := 0; i < len(a.Algorithms); i++ {
		a.Algorithms[i].DebugInfo = d
		b.Algorithms[i].DebugInfo = d
		if a.Algorithms[i] != b.Algorithms[i] {
			return false
		}
	}
	for i := 0; i < len(a.Transitions); i++ {
		a.Transitions[i].DebugInfo = d
		b.Transitions[i].DebugInfo = d
		if a.Transitions[i] != b.Transitions[i] {
			return false
		}
	}
	for i := 0; i < len(a.States); i++ {
		if a.States[i].Name != b.States[i].Name {
			return false
		}
		if len(a.States[i].ECActions) != len(b.States[i].ECActions) {
			return false
		}
		for j := 0; j < len(a.States[i].ECActions); j++ {
			a.States[i].ECActions[j].DebugInfo = d
			b.States[i].ECActions[j].DebugInfo = d
			if a.States[i].ECActions[j] != b.States[i].ECActions[j] {
				return false
			}
		}
	}
	return true
}

func compositeFbsSame(a CompositeFB, b CompositeFB) bool {
	if len(a.FBs) != len(b.FBs) {
		return false
	}
	if len(a.DataConnections) != len(b.DataConnections) {
		return false
	}
	if len(a.EventConnections) != len(b.EventConnections) {
		return false
	}

	for i := 0; i < len(a.FBs); i++ {
		a.FBs[i].DebugInfo = d
		b.FBs[i].DebugInfo = d

		if len(a.FBs[i].Parameter) != len(b.FBs[i].Parameter) {
			return false
		}
		for j := 0; j < len(a.FBs[i].Parameter); j++ {
			a.FBs[i].Parameter[j].DebugInfo = d
			b.FBs[i].Parameter[j].DebugInfo = d
		}
		if !reflect.DeepEqual(a.FBs[i], b.FBs[i]) {
			return false
		}
	}

	for i := 0; i < len(a.DataConnections); i++ {
		a.DataConnections[i].DebugInfo = d
		b.DataConnections[i].DebugInfo = d
		if a.DataConnections[i] != b.DataConnections[i] {
			return false
		}
	}

	for i := 0; i < len(a.EventConnections); i++ {
		a.EventConnections[i].DebugInfo = d
		b.EventConnections[i].DebugInfo = d
		if a.EventConnections[i] != b.EventConnections[i] {
			return false
		}
	}

	return true
}

func siFbsSame(a ServiceFB, b ServiceFB) bool {
	a.Autogenerate.DebugInfo = d
	b.Autogenerate.DebugInfo = d

	return reflect.DeepEqual(a, b)
}


text:
namespace co {

//------ co.System has a facet named 'system', of type co.ISystem ------//

co::IInterface* System_co_ISystem::getInterface()
{
	return co::typeOf<co::ISystem>::get();
}

co::IPort* System_co_ISystem::getFacet()
{
	co::IComponent* component = static_cast<co::IComponent*>( co::getType( "co.System" ) );
	assert( component );
	co::IPort* facet = static_cast<co::IPort*>( component->getMember( "system" ) );
	assert( facet );
	return facet;
}

//------ System_Base ------//

System_Base::System_Base()
{
	// empty
}

System_Base::~System_Base()
{
	// empty
}

co::IObject* System_Base::getProvider()
{
	return this;
}

void System_Base::serviceRetain()
{
	incrementRefCount();
}

void System_Base::serviceRelease()
{
	decrementRefCount();
}

co::IComponent* System_Base::getComponent()
{
	co::IType* type = co::getType( "co.System" );
	assert( type->getKind() == co::TK_COMPONENT );
	return static_cast<co::IComponent*>( type );
}

co::IService* System_Base::getServiceAt( co::IPort* port )
{
	checkValidPort( port );
	co::IService* res = NULL;
	switch( port->getIndex() )
	{
	case 0:		res = static_cast<co::ISystem*>( this ); break;
	default:	raiseUnexpectedPortIndex();
	}
	return res;
}

void System_Base::setServiceAt( co::IPort* receptacle, co::IService* service )
{
	checkValidReceptacle( receptacle );
	raiseUnexpectedPortIndex();
	CORAL_UNUSED( service );
}

} // namespace co


text:
/*    */ package com.hundsun.network.gates.wulin.remote.service.pojo;
/*    */
/*    */ import com.hundsun.network.gates.luosi.wulin.reomte.enums.EnumUserResultErrors;
/*    */ import com.hundsun.network.gates.luosi.wulin.reomte.request.SystemMessageRequest;
/*    */ import com.hundsun.network.gates.luosi.wulin.reomte.result.SystemMessageResult;
/*    */ import com.hundsun.network.gates.luosi.wulin.reomte.service.RemoteSystemMessageService;
/*    */ import com.hundsun.network.gates.wulin.biz.service.BaseService;
/*    */ import com.hundsun.network.gates.wulin.biz.service.message.SystemMessageService;
/*    */ import org.apache.commons.logging.Log;
/*    */ import org.springframework.beans.factory.annotation.Autowired;
/*    */ import org.springframework.stereotype.Service;
/*    */
/*    */ @Service("remoteSystemMessageService")
/*    */ public class RemoteSystemMessageServiceImpl extends BaseService
/*    */   implements RemoteSystemMessageService
/*    */ {
/*    */
/*    */   @Autowired
/*    */   private SystemMessageService systemMessageService;
/*    */
/*    */   public SystemMessageResult sendSystemMessage(SystemMessageRequest request)
/*    */   {
/* 38 */     this.log.debug("RemoteSystemMessageService sendSystemMessage");
/* 39 */     SystemMessageResult systemMessageResult = new SystemMessageResult();
/*    */     try {
/* 41 */       systemMessageResult = this.systemMessageService.sendSystemMessage(request);
/*    */     } catch (Exception e) {
/* 43 */       systemMessageResult.setErrorNO(Integer.valueOf(EnumUserResultErrors.INTERNAL_ERROR.getValue()));
/* 44 */       systemMessageResult.setErrorInfo(EnumUserResultErrors.INTERNAL_ERROR.getInfo());
/* 45 */       return systemMessageResult;
/*    */     }
/* 47 */     return systemMessageResult;
/*    */   }
/*    */ }

/* Location:           E:\__安装归档\linquan-20161112\deploy16\wulin\webroot\WEB-INF\classes\
 * Qualified Name:     com.hundsun.network.gates.wulin.remote.service.pojo.RemoteSystemMessageServiceImpl
 * JD-Core Version:    0.6.0
 */