text:
namespace Js
{
    template <typename TStrongRef> class RemoteWeakReference;
};

namespace Memory
{
// Forward declarations
template <typename SizePolicy> class WeakReferenceHashTable;
class Recycler;

///
/// This class is represents a weak reference handle object
/// It's a proxy to the actual strong reference itself
/// This is an entry in the weak reference hash table.
/// When a weak reference is created, the strong reference is set to
/// point to an object.
/// When the referenced object is collected, the strong reference is set to NULL
///
/// Clients should not use this class but instead use RecyclerWeakReference<type>
/// which provides for automatic type conversion of the underlying reference
class RecyclerWeakReferenceBase
{
public:
    friend class Recycler;

    template <typename SizePolicy> friend class WeakReferenceHashTable;
    template <typename TStrongRef> friend class Js::RemoteWeakReference;

protected:

    FieldNoBarrier(char*) strongRef;
    FieldNoBarrier(HeapBlock *) strongRefHeapBlock;
    FieldNoBarrier(HeapBlock *) weakRefHeapBlock;
    FieldNoBarrier(RecyclerWeakReferenceBase*) next;
#if DBG
#if ENABLE_RECYCLER_TYPE_TRACKING
    FieldNoBarrier(type_info const *) typeInfo;
#endif

#if defined TRACK_ALLOC && defined(PERF_COUNTERS)
    FieldNoBarrier(PerfCounter::Counter *) counter;
#endif
#endif
};

/// Wrapper class template that can be used to acquire the underlying strong reference from the weak reference
template<typename T>
class RecyclerWeakReference: public RecyclerWeakReferenceBase
{
public:
    // Fast get of the strong reference- this might return a wrong result if the recycler is in sweep so callers
    // should never call this during sweep
    inline T* FastGet() const
    {
        return ((T*) strongRef);
    }

    inline T* Get() const
    {
        char * ref = this->strongRef;
        return (T*)ref;
    }

    inline T** GetAddressOfStrongRef()
    {
        return (T**)&strongRef;
    }

};

template <class T>
class WeakReferenceCache
{
private:
    RecyclerWeakReference<T> * weakReference;
public:
    WeakReferenceCache() : weakReference(nullptr) {};
    RecyclerWeakReference<T> * GetWeakReference(Recycler * recycler)
    {
        RecyclerWeakReference<T> * weakRef = this->weakReference;
        if (weakRef == nullptr)
        {
            weakRef = recycler->CreateWeakReferenceHandle((T*)this);
            this->weakReference = weakRef;
        }
        return weakRef;
    }
};

///
/// Hashtable class that maps strong references to weak references
/// This is slightly unique in that the weak reference is a complete entry in the hashtable
/// but is treated as the value for the client. The key is the strong reference.
/// The hash table is a standard closed-addressing hash table where the strong references are
/// hashed into buckets, and then stored in that buckets corresponding doubly linked list
/// The hash-table is resized when its load factor exceeds a constant
/// The buckets are allocated using the HeapAllocator. Individual entries are recycler allocated.
///
template <typename SizePolicy>
class WeakReferenceHashTable
{
    static const int MaxAverageChainLength = 1;

    HeapAllocator* allocator;
    RecyclerWeakReferenceBase** buckets;
    uint count;
    uint size;
    RecyclerWeakReferenceBase* freeList;
    int modFunctionIndex;

public:
    WeakReferenceHashTable(uint size, HeapAllocator* allocator):
        count(0),
        size(0),
        modFunctionIndex(UNKNOWN_MOD_INDEX),
        allocator(allocator),
        freeList(nullptr)
    {
        this->size = SizePolicy::GetSize(size, &modFunctionIndex);
        buckets = AllocatorNewArrayZ(HeapAllocator, allocator, RecyclerWeakReferenceBase*, this->size);
    }

    ~WeakReferenceHashTable()
    {
        AllocatorDeleteArray(HeapAllocator, allocator,  size, buckets);
    }

    RecyclerWeakReferenceBase* Add(char* strongReference, Recycler * recycler)
    {
        uint targetBucket = HashKeyToBucket(strongReference, size);
        RecyclerWeakReferenceBase* entry = FindEntry(strongReference, targetBucket);
        if (entry != nullptr)
        {
            return entry;
        }

        return Create(strongReference, targetBucket, recycler);
    }

    bool FindOrAdd(char* strongReference, Recycler *recycler, RecyclerWeakReferenceBase **ppWeakRef)
    {
        Assert(ppWeakRef);

        uint targetBucket = HashKeyToBucket(strongReference, size);
        RecyclerWeakReferenceBase* entry = FindEntry(strongReference, targetBucket);
        if (entry != nullptr)
        {
            *ppWeakRef = entry;
            return false;
        }

        entry = Create(strongReference, targetBucket, recycler);
        *ppWeakRef = entry;
        return true;
    }

#ifdef RECYCLER_TRACE_WEAKREF
    void DumpNode(RecyclerWeakReferenceBase* node)
    {
        Output::Print(_u("[ 0x%08x { 0x%08x, 0x%08x }]"), node, node->strongRef, mode->next);
    }

    void Dump()
    {
        RecyclerWeakReferenceBase *current;
        Output::Print(_u("HashTable with %d buckets and %d nodes\n"), this->size, this->count);

        for (uint i=0;i<size;i++) {
            Output::Print(_u("Bucket %d (0x%08x) ==> "), i, &buckets[i]);
            for (current = buckets[i] ; current != nullptr; current = current->next) {
                DumpNode(current);
            }
            Output::Print(_u("\n"));
        }
    }
#endif

    bool TryGetValue(char* strongReference, RecyclerWeakReferenceBase** weakReference)
    {
        RecyclerWeakReferenceBase* current = FindEntry(strongReference, HashKeyToBucket(strongReference, size));
        if (current != nullptr)
        {
            *weakReference = current;
            return true;
        }
        return false;
    }

    void Remove(char* key, RecyclerWeakReferenceBase** pOut)
    {
        uint val = HashKeyToBucket(key, size);
        RecyclerWeakReferenceBase ** pprev = &buckets[val];
        RecyclerWeakReferenceBase *current = *pprev;
        while (current)
        {
            if (DefaultComparer<char*>::Equals(key, current->strongRef))
            {
                 *pprev = current->next;
                if (pOut != nullptr)
                {
                    (*pOut) = current;
                }
                count--;

#ifdef RECYCLER_TRACE_WEAKREF
                Output::Print(_u("Remove 0x%08x to bucket %d, count is %d\n"), current, val, count);
#endif
                break;
            }
            pprev = &current->next;
            current = *pprev;
        }
    }

    uint Count()
    {
        return count;
    }

    void Remove(char* key)
    {
        Remove(key, nullptr);
    }

    template <class Func>
    void Map(Func fn)
    {
        uint removed = 0;
#if DEBUG
        uint countedEntries = 0;
#endif

        for (uint i=0;i<size;i++)
        {
            RecyclerWeakReferenceBase ** pprev = &buckets[i];
            RecyclerWeakReferenceBase *current = *pprev;
            while (current)
            {
                if (fn(current))
                {
                    pprev = &current->next;
#if DEBUG
                    countedEntries++;
#endif
                }
                else
                {
                    // remove
                    *pprev = current->next;
                    removed++;
                }
                current = *pprev;
            }
        }

        Assert(removed <= count);
        count -= removed;

#if DEBUG
        Assert(countedEntries == count);
#endif
    }

private:
    // If density is a compile-time constant, then we can optimize (avoids division)
    // Sometimes the compiler can also make this optimization, but this way is guaranteed.
    template< uint density > bool IsDenserThan() const
    {
        return count > (size * density);
    }

    RecyclerWeakReferenceBase * FindEntry(char* strongReference, uint targetBucket)
    {
        for (RecyclerWeakReferenceBase * current = buckets[targetBucket] ; current != nullptr; current = current->next)
        {
            if (DefaultComparer<char*>::Equals(strongReference, current->strongRef))
            {
                return current;
            }
        }

        return nullptr;
    }

    hash_t HashKeyToBucket(char* strongReference, int size)
    {
        hash_t hashCode = DefaultComparer<char*>::GetHashCode(strongReference);
        return SizePolicy::GetBucket(hashCode, size, modFunctionIndex);
    }

    void AddEntry(RecyclerWeakReferenceBase* entry, RecyclerWeakReferenceBase** bucket)
    {
        RecyclerWeakReferenceBase* first = (*bucket);

        entry->next = first;
        (*bucket) = entry;
    }

    void Resize(int newSize)
    {
#if DEBUG
        uint copiedEntries = 0;
#endif
        RecyclerWeakReferenceBase** newBuckets = AllocatorNewArrayZ(HeapAllocator, allocator, RecyclerWeakReferenceBase*, newSize);

        for (uint i=0; i < size; i++)
        {
            RecyclerWeakReferenceBase* current = buckets[i];
            while (current != nullptr)
            {
                int targetBucket = HashKeyToBucket(current->strongRef, newSize);
                RecyclerWeakReferenceBase* next = current->next; // Cache the next pointer

                AddEntry(current, &newBuckets[targetBucket]);
#if DEBUG
                copiedEntries++;
#endif
                current = next;
            }
        }

        AllocatorDeleteArray(HeapAllocator, allocator, size, buckets);
        size = newSize;
        buckets = newBuckets;
#if DEBUG
        Assert(this->count == copiedEntries);
#endif
    }

    RecyclerWeakReferenceBase* Create(char* strongReference, uint targetBucket, Recycler * recycler)
    {
        Assert(HashKeyToBucket(strongReference, size) == targetBucket);
        Assert(!FindEntry(strongReference, targetBucket));

        if (IsDenserThan<MaxAverageChainLength>())
        {
#ifdef RECYCLER_TRACE_WEAKREF
            Output::Print(_u("Count is %d\n"), this->count);
#endif
            Resize(SizePolicy::GetSize(size*2, &modFunctionIndex));
            // After resize - we will need to recalculate the bucket
            targetBucket = HashKeyToBucket(strongReference, size);
        }

        RecyclerWeakReferenceBase* entry;
        entry = AllocatorNewBase(Recycler, recycler, AllocWeakReferenceEntry, RecyclerWeakReferenceBase);
        entry->strongRef = strongReference;
        entry->strongRefHeapBlock = recycler->FindHeapBlock(strongReference);
        Assert(entry->strongRefHeapBlock != nullptr);

        HeapBlock * weakRefHeapBlock = recycler->FindHeapBlock(entry);
        Assert(!weakRefHeapBlock->IsLargeHeapBlock() || ((LargeHeapBlock*)weakRefHeapBlock)->InPageHeapMode());
        entry->weakRefHeapBlock = weakRefHeapBlock;

#ifdef RECYCLER_TRACE_WEAKREF
        Output::Print(_u("Add WeakRef 0x%08x for StrongRef %p to bucket %d\n"), entry, strongReference, targetBucket);
#endif
        AddEntry(entry, &buckets[targetBucket]);
        count++;
#if DBG
#if ENABLE_RECYCLER_TYPE_TRACKING
        entry->typeInfo = nullptr;
#endif
#if defined(TRACK_ALLOC) && defined(PERF_COUNTERS)
        entry->counter = nullptr;
#endif
#endif
        return entry;
    }
};
}


text:
function difference = GetCrossSubjectStats(timecourse,tResponse,regressor_events,Cmap)

% Find and plot the time points at which any two experimental conditions
% evoked a significantly different timecourse of activity.
%
% difference = GetCrossSubjectStats(timecourse,tResponse,regressor_events)
%
% Uses anova1 and multcompare, alpha = 0.05 and tukey-kramer
% multiple-comparisons correction, for statistical tests.
%
% INPUTS:
% - timecourse is an nComponents x nTrialTypes cell matrix, each of which
% contains an nSubjects x nTimePoints matrix of doubles.
% timecourse{i,j}(k,l) is the mean activity in component i evoked by event
% type j for subject k at time point l.  It is an output of
% GetGroupSvdResults.m.
% - tResponse is a nTimePoints-element array of latencies (in ms) relative
% to the locking event.
% - regressor_events is a nTrialTypes cell matrix of strings indicating the
% event types you are comparing.
%
% OUTPUTS:
% - difference is a matrix of size (nComponents,nTimePoints,nTrialTypes,
% nTrialTypes).  difference(i,j,k,l)=1 if, in component i at time j, event
% l evoked significantly more positive activity than event k.  =-1 if more
% negative, and =NaN otherwise.
%
% Created 7/13/12 by DJ.
% Updated 7/18/12 by DJ - Made into function, plots all on one figure.
% Updated 10/2/13 by DJ - Added Cmap input, floating legend

%% CALCULATE
% Get constants
nComponents = size(timecourse,1);
nTrialTypes = size(timecourse,2);
nSubjects = size(timecourse{1},1);
nT = size(timecourse{1},2);

if nargin<4 || isempty(Cmap)
    Cmap = distinguishable_colors(nTrialTypes,{'w','k'}); % don't allow black or white
end

% Get p values using anova1 and multcompare
difference = nan(nComponents,nT,nTrialTypes,nTrialTypes); % sign of significant differences between classes
disp('Getting p values...');
hwait = waitbar(0,'Getting p values...');
for j=1:nT %nTimepoints
    waitbar(j/nT,hwait);
    for i=1:nComponents
        % Perform statistical test
        X = nan(nSubjects,nTrialTypes); % reformat for anova1
        for k=1:nTrialTypes
            X(:,k) = timecourse{i,k}(:,j);
        end
        [~,~,stats] = anova1(X,regressor_events,'off');
        comparison = multcompare(stats,'alpha',0.05,'display','off','ctype','tukey-kramer'); % correct for multiple comparisons (across conditions, not time points!)

        % Find points with significant differences (in positive and negative direction separately)
        sig_pos = find(comparison(:,3)>0);
        sig_neg = find(comparison(:,5)<0);
        % Register these points in the difference matrix
        for k=1:numel(sig_pos)
            difference(i,j,comparison(sig_pos(k),1),comparison(sig_pos(k),2)) = -1;
            difference(i,j,comparison(sig_pos(k),2),comparison(sig_pos(k),1)) = 1;
        end
        for k=1:numel(sig_neg)
            difference(i,j,comparison(sig_neg(k),1),comparison(sig_neg(k),2)) = 1;
            difference(i,j,comparison(sig_neg(k),2),comparison(sig_neg(k),1)) = -1;
        end
    end
end
% Finish up
close(hwait);
disp('Done!')

%% PLOT

% colors = {'r' 'g' 'b' 'c' 'm' 'y' 'k' 'r--' 'g--' 'b--'};

% figure(55);
clf;
for j=1:nTrialTypes
    for i=1:nComponents
        % Plot lines where differences are significant
        subplot(nComponents,nTrialTypes,(i-1)*nTrialTypes+j)
        cla; hold on;
        for k=1:nTrialTypes
            plot(tResponse,difference(i,:,j,k)*k,'color',Cmap(k,:),'linewidth',2);
        end
        % Annotate plot
        plot([tResponse(1) tResponse(end)],[0 0],'color',Cmap(j,:),'linewidth',2);
        axis([tResponse(1), tResponse(end), -nTrialTypes-1, nTrialTypes+1]);
        set(gca,'xgrid','on')
        plot(get(gca,'xlim'),[0 0],'k:','linewidth',2);
        ylabel(sprintf('Component %d',i));
    end
    % Annotate plots futher
    xlabel('time (ms)'); % only on bottom row
    subplot(nComponents,nTrialTypes,j);
    title(sprintf('%s vs. all others\n(One-Way Anova with multcompare, p=0.05)',regressor_events{j})); % only on top row
    subplot(nComponents,nTrialTypes,1);
%     legend(regressor_events,'Location','NorthWest'); % only on top-left plot
end
MakeLegend(Cmap,regressor_events,2);

redpajama_set_name: RedPajamaGithub


text:
package org.lockss.util;

import org.lockss.test.*;

import java.util.Arrays;

/**
 * This is the test class for org.lockss.util.NumberUtil
 */
public class TestNumberUtil extends LockssTestCase {
  @SuppressWarnings("rawtypes")
  public static Class[] testedClasses = {
    org.lockss.util.NumberUtil.class
  };

  public TestNumberUtil(String msg) {
    super(msg);
  }

  /**
   * Test constructSequence() with delta 1.
   */
  public final void testConstructSequenceIntInt() {
    // Increasing sequences
    assertTrue(Arrays.equals(new int[]{0}, NumberUtil.constructSequence(0,0)));
    assertTrue(Arrays.equals(new int[]{0,1,2}, NumberUtil.constructSequence(0,2)));
    assertTrue(Arrays.equals(new int[]{-2,-1,0}, NumberUtil.constructSequence(-2,0)));

    // Decreasing sequences
    assertTrue(Arrays.equals(new int[]{2,1,0}, NumberUtil.constructSequence(2,0)));
    assertTrue(Arrays.equals(new int[]{0,-1,-2}, NumberUtil.constructSequence(0,-2)));

    // No exception should occur with a delta of 1
    try {
      NumberUtil.constructSequence(0,0);
      NumberUtil.constructSequence(0,1);
      NumberUtil.constructSequence(0,2);
      NumberUtil.constructSequence(0,-1);
      NumberUtil.constructSequence(-1,0);
      NumberUtil.constructSequence(-10,10);
    } catch (IllegalArgumentException e) {
      fail("Should not throw IllegalArgumentException with unit delta!");
    }
  }

  /**
   * Test constructSequence() with specified delta.
   */
  public final void testConstructSequenceIntIntInt() {
    // Equal start and end with any delta should produce one number.
    for (int i=-5; i<5; i++) {
      int[] exp = new int[]{i};
      assertTrue(Arrays.equals(exp, NumberUtil.constructSequence(i,i,0)));
      assertTrue(Arrays.equals(exp, NumberUtil.constructSequence(i,i,5)));
      assertTrue(Arrays.equals(exp, NumberUtil.constructSequence(i,i,-5)));
      assertTrue(Arrays.equals(exp, NumberUtil.constructSequence(i,i,999)));
    }
    // Increasing sequences
    assertTrue(Arrays.equals(new int[]{0,2}, NumberUtil.constructSequence(0,2,2)));
    assertTrue(Arrays.equals(new int[]{0,2,4}, NumberUtil.constructSequence(0,4,2)));
    assertTrue(Arrays.equals(new int[]{-3,0,3}, NumberUtil.constructSequence(-3,3,3)));
    // Inverted delta should get corrected
    assertTrue(Arrays.equals(new int[]{-3,-1,1,3}, NumberUtil.constructSequence(-3,3,-2)));

    // Decreasing sequences
    assertTrue(Arrays.equals(new int[]{2,0}, NumberUtil.constructSequence(2,0,2)));
    assertTrue(Arrays.equals(new int[]{4,2,0}, NumberUtil.constructSequence(4,0,2)));
    assertTrue(Arrays.equals(new int[]{3,0,-3}, NumberUtil.constructSequence(3,-3,3)));
    // Inverted delta should get corrected
    assertTrue(Arrays.equals(new int[]{3,1,-1,-3}, NumberUtil.constructSequence(3,-3,-2)));

    // Invalid delta should produce exception
    try {
      NumberUtil.constructSequence(0,2,3);
      fail("Should have thrown IllegalArgumentException due to invalid delta.");
    } catch (IllegalArgumentException e) {
      // Expected
    }
  }

  public final void testConstructPaddedIntSequence() {
    assertIsomorphic(
        Arrays.asList(new String[]{"001", "002", "003"}),
        NumberUtil.constructPaddedIntSequence("001", "003", 1)
    );
    assertIsomorphic(
        Arrays.asList(new String[]{"001", "003"}),
        NumberUtil.constructPaddedIntSequence("001", "003", 2)
    );
    assertIsomorphic(
        Arrays.asList(new String[]{"1", "2", "3"}),
        NumberUtil.constructPaddedIntSequence("1", "3", 1)
    );
    assertIsomorphic(
        Arrays.asList(new String[]{"9", "10", "11"}),
        NumberUtil.constructPaddedIntSequence("9", "11", 1)
    );
    assertIsomorphic(
        Arrays.asList(new String[]{"09", "10", "11"}),
        NumberUtil.constructPaddedIntSequence("09", "11", 1)
    );

    // Should throw exception on inconsistent args
    try {
      NumberUtil.constructPaddedIntSequence("001", "003", 3);
      fail("Should throw exception");
    } catch (IllegalArgumentException e) {
      /*Expected*/
    }
    try {
      NumberUtil.constructPaddedIntSequence("001", "006", 2);
      fail("Should throw exception");
    } catch (IllegalArgumentException e) {
      /*Expected*/
    }
    // Zero-padded and not
    try {
      NumberUtil.constructPaddedIntSequence("1", "003", 1);
      fail("Should throw exception");
    } catch (IllegalArgumentException e) {
      /*Expected*/
    }
  }

  public final void testConstructRomanSequence() {
    assertEquals(Arrays.asList(new String[]{"I", "II", "III", "IV", "V"}),
        NumberUtil.constructRomanSequence("I","V",1));
    // Lower case
    assertEquals(Arrays.asList(new String[]{"i", "ii", "iii", "iv", "v"}),
        NumberUtil.constructRomanSequence("i","v",1));
    // Unnormalised 5 - 11 // TODO Should iiix be seen as 7?
    assertEquals(Arrays.asList(new String[]{"iv", "v", "vi", "vii", "viii", "ix", "x", "xi"}),
        NumberUtil.constructRomanSequence("iiii","iiix",1));
    // Unnormalised 5 - 7
    assertEquals(Arrays.asList(new String[]{"iv", "v", "vi", "vii"}),
        NumberUtil.constructRomanSequence("iiii","iiiiiii",1));
    // Decrementing sequence
    assertEquals(Arrays.asList(new String[]{"V", "IV", "III", "II", "I"}),
        NumberUtil.constructRomanSequence("V","I",1));
    // Incrementing by 3
    assertEquals(Arrays.asList(new String[]{"II", "V", "VIII", "XI"}),
        NumberUtil.constructRomanSequence("II","XI",3));
    // Mixed Roman and Arabic args; roman output
    /*assertEquals(Arrays.asList(new String[]{"I", "II", "III"}),
        NumberUtil.constructRomanSequence("1","III",1));*/
    // Try and construct a sequence with args that don't add up
    try {
      NumberUtil.constructRomanSequence("II","X",3);
      fail("Exception expected");
    } catch (Exception e) {
      // Expected exception
    }
    // Mixed Roman and Arabic are not allowed
    try {
      NumberUtil.constructRomanSequence("1","III",1);
      fail("Exception expected");
    } catch (Exception e) {
      // Expected exception
    }
  }

  public final void testConstructAlphabeticSequence() {

    assertIsomorphic(
        Arrays.asList(new String[]{"a", "b", "c"}),
        NumberUtil.constructAlphabeticSequence("a", "c", 1)
    );
    assertIsomorphic(
        Arrays.asList(new String[]{"aaa", "ana", "baa"}),
        NumberUtil.constructAlphabeticSequence("aaa", "baa", 26*13)
    );

    // Try strings of different lengths
    try {
      NumberUtil.constructAlphabeticSequence("a", "aa", 1);
      fail("Should throw exception for different length strings");
    } catch (IllegalArgumentException e) {
      /*Expected exception*/
    }

    // Should throw exception on inconsistent args - diff not divisible by delta
    try {
      NumberUtil.constructAlphabeticSequence("001", "003", 3);
      fail("Should throw exception for inconsistent args");
    } catch (IllegalArgumentException e) {
      /*Expected*/
    }
    try {
      NumberUtil.constructAlphabeticSequence("001", "006", 2);
      fail("Should throw exception for inconsistent args");
    } catch (IllegalArgumentException e) {
      /*Expected*/
    }
  }

  /**
   * Test whether strings are recognised as digits only up to a length parsable
   * as integer.
   */
  public final void testIsIntegerDigits() {
    assertTrue(NumberUtil.isIntegerDigits("100"));
    assertTrue(NumberUtil.isIntegerDigits("0"));
    assertTrue(NumberUtil.isIntegerDigits("1"));
    assertTrue(NumberUtil.isIntegerDigits("123456789"));
    // Part of the contract of this method is that strings yielding true
    // should parse as integers
    assertTrue(NumberUtil.isInteger("100"));
    assertTrue(NumberUtil.isInteger("0"));
    assertTrue(NumberUtil.isInteger("1"));
    assertTrue(NumberUtil.isInteger("123456789"));

    // Too long
    assertFalse(NumberUtil.isIntegerDigits("1234567890"));
    // Not digits
    assertFalse(NumberUtil.isIntegerDigits("99.9"));
    assertFalse(NumberUtil.isIntegerDigits("not an integer"));
    assertFalse(NumberUtil.isIntegerDigits("100 non numbers"));
    assertFalse(NumberUtil.isIntegerDigits(""));
    assertFalse(NumberUtil.isIntegerDigits(null));
  }

  /**
   * Test whether strings parse as integers.
   */
  public final void testIsInteger() {
    assertTrue(NumberUtil.isInteger("100"));
    assertFalse(NumberUtil.isInteger("99.9"));
    assertFalse(NumberUtil.isInteger("not an integer"));
    assertFalse(NumberUtil.isInteger("100 non numbers"));
    assertFalse(NumberUtil.isInteger(""));
    assertFalse(NumberUtil.isInteger(null));
  }

  /**
   * Test whether strings parse as numbers.
   */
  public final void testIsNumber() {
    assertTrue(NumberUtil.isNumber("100"));
    assertTrue(NumberUtil.isNumber("C"));
    assertTrue(NumberUtil.isNumber("XVII"));
    assertTrue(NumberUtil.isNumber("N"));

    // signed numbers
    assertTrue(NumberUtil.isNumber("-100"));
    assertTrue(NumberUtil.isNumber("-00"));
    assertTrue(NumberUtil.isNumber("-123456789"));
    assertTrue(NumberUtil.isNumber("+100"));
    assertTrue(NumberUtil.isNumber("+00"));
    assertTrue(NumberUtil.isNumber("+123456789"));

    // signed Roman numbers not allowed
    assertFalse(NumberUtil.isNumber("+C"));
    assertFalse(NumberUtil.isNumber("-XVII"));

    // Not numbers
    assertFalse(NumberUtil.isNumber("99.9"));
    assertFalse(NumberUtil.isNumber("not an integer"));
    assertFalse(NumberUtil.isNumber("100 non numbers"));
    assertFalse(NumberUtil.isNumber(""));
    assertFalse(NumberUtil.isNumber(null));

    // Strings represent non-normal roman numbers:
    assertTrue(NumberUtil.isNumber("Viv"));
    assertTrue(NumberUtil.isNumber("Vic"));
    assertTrue(NumberUtil.isNumber("Civic"));
    assertTrue(NumberUtil.isNumber("Livid"));
    assertTrue(NumberUtil.isNumber("Mivvi"));
    assertTrue(NumberUtil.isNumber("Mill"));
  }

  /**
   * Test whether strings contain digits.
   */
  public final void testContainsDigit() {
    assertTrue(NumberUtil.containsDigit("1"));
    assertTrue(NumberUtil.containsDigit("a1"));
    assertTrue(NumberUtil.containsDigit("1a"));
    assertTrue(NumberUtil.containsDigit("a1a"));
    assertTrue(NumberUtil.containsDigit("1a1"));
    assertTrue(NumberUtil.isMixedFormat("A string with 1 digit!"));

    assertFalse(NumberUtil.containsDigit(""));
    assertFalse(NumberUtil.containsDigit(null));
    assertFalse(NumberUtil.containsDigit("XI"));
    assertFalse(NumberUtil.containsDigit("a string"));
  }

  /**
   * Test whether strings are mixed format.
   */
  public final void testIsMixedFormat() {
    assertTrue(NumberUtil.isMixedFormat("a1"));
    assertTrue(NumberUtil.isMixedFormat("1a"));
    assertTrue(NumberUtil.isMixedFormat("2a1"));
    assertTrue(NumberUtil.isMixedFormat("a1-1"));
    assertTrue(NumberUtil.isMixedFormat("a1a"));
    assertTrue(NumberUtil.isMixedFormat("A mixed format string with 1 digit!"));

    // Single format strings are not mixed format
    assertFalse(NumberUtil.isMixedFormat(""));
    assertFalse(NumberUtil.isMixedFormat("XI"));
    assertFalse(NumberUtil.isMixedFormat("a string"));
    assertFalse(NumberUtil.isMixedFormat("1"));
    assertFalse(NumberUtil.isMixedFormat("200"));
    // Roman numeral tokens are not parsed
    assertFalse(NumberUtil.isMixedFormat("vol-XI"));
  }

  /**
   * Test whether strings parse as Roman numbers.
   */
  public final void testIsRomanNumber() {
    assertTrue(NumberUtil.isRomanNumber("C"));
    assertTrue(NumberUtil.isRomanNumber("XVII"));
    assertTrue(NumberUtil.isRomanNumber("N"));

    // Try lower and mixed case
    assertTrue(NumberUtil.isRomanNumber("c"));
    assertTrue(NumberUtil.isRomanNumber("xvII"));
    assertTrue(NumberUtil.isRomanNumber("n"));

    // Unnormalized Roman strings
    assertTrue(NumberUtil.isRomanNumber("XVIIIII"));
    assertTrue(NumberUtil.isNumber("XVIIIII"));
    assertTrue(NumberUtil.isRomanNumber("clivic"));
    assertTrue(NumberUtil.isNumber("clivic"));

    // Strings not intended to represent Roman numerals can be taken so
    // when normalisation is not enforced:
    checkUnnormalisedRomanNumber("Viv");
    checkUnnormalisedRomanNumber("Vic");
    checkUnnormalisedRomanNumber("Vid");
    checkUnnormalisedRomanNumber("Civic");
    checkUnnormalisedRomanNumber("Livid");
    checkUnnormalisedRomanNumber("Mivvi");
    checkUnnormalisedRomanNumber("Mill");
    // TODO Is this really what we want by default?

    // Non-Roman strings
    assertFalse(NumberUtil.isRomanNumber("clinic"));
    assertFalse(NumberUtil.isNumber("clinic"));
  }

  /**
   * Test whether unnormalised strings parse as Roman numbers in general, and
   * fail when parsing with normalisation..
   */
  protected final void checkUnnormalisedRomanNumber(String s) {
    assertTrue(NumberUtil.isRomanNumber(s));
    assertFalse(NumberUtil.isNormalisedRomanNumber(s));
  }

  public final void testIsNumericalRange() {
    // Integer ranges
    assertTrue(NumberUtil.isNumericalRange("1-1"));
    assertTrue(NumberUtil.isNumericalRange("1-2"));
    assertTrue(NumberUtil.isNumericalRange("1-9"));
    assertTrue(NumberUtil.isNumericalRange("1-10"));
    // Roman numeral ranges
    assertTrue(NumberUtil.isNumericalRange("C-CLXVII"));
    assertTrue(NumberUtil.isNumericalRange("I-VI"));
    assertTrue(NumberUtil.isNumericalRange("V-C")); // compared numerically not lexically
    assertTrue(NumberUtil.isNumericalRange("C-C"));
    // Mixed ranges
    assertTrue(NumberUtil.isNumericalRange("I-4"));
    assertTrue(NumberUtil.isNumericalRange("1-V"));

    // Single volumes are not ranges
    assertFalse(NumberUtil.isNumericalRange("1"));
    assertFalse(NumberUtil.isNumericalRange("V"));
    // Hyphenated strings with unparseable volumes are not ranges
    assertFalse(NumberUtil.isNumericalRange("ROMAN-NUMERALS"));
    assertFalse(NumberUtil.isNumericalRange("LXV-LXVIIP"));
    assertFalse(NumberUtil.isNumericalRange("one - 2"));
    assertFalse(NumberUtil.isNumericalRange("null-null"));
    // Descending values are not ranges
    assertFalse(NumberUtil.isNumericalRange("11-9"));
    assertFalse(NumberUtil.isNumericalRange("10-01"));
    assertFalse(NumberUtil.isNumericalRange("C-V")); // compared numerically not lexically
    // Not a range
    assertFalse(NumberUtil.isNumericalRange("1-2-3"));
    // Valid string ranges are not numerical ranges
    assertFalse(NumberUtil.isNumericalRange("s1-s2"));
  }

  public final void testPadNumbers() {
    assertEquals("001", NumberUtil.padNumbers("1", 3));
    assertEquals("001", NumberUtil.padNumbers("01", 3));
    assertEquals("001", NumberUtil.padNumbers("001", 3));
    assertEquals("1000", NumberUtil.padNumbers("1000", 3));

    // Padding to <1 does nothing to the input string
    assertEquals("1", NumberUtil.padNumbers("1", 0));
    assertEquals("001", NumberUtil.padNumbers("001", 0));
    assertEquals("001", NumberUtil.padNumbers("001", 1));
    assertEquals("001", NumberUtil.padNumbers("001", -1));
    assertEquals("1", NumberUtil.padNumbers("1", 1));
    assertEquals("1", NumberUtil.padNumbers("1", -1));

    // Pad numbers
    assertEquals("001", NumberUtil.padNumbers(1, 3));
    assertEquals("1000", NumberUtil.padNumbers(1000, 3));
    assertEquals("1", NumberUtil.padNumbers(1, 0));

  }

  /**
   * Test consecutive numbers represented as integers.
   */
  public final void testAreConsecutiveIntInt() {
    assertTrue(  NumberUtil.areConsecutive(0,  1) );
    assertTrue(  NumberUtil.areConsecutive(1,  2) );
    assertTrue(  NumberUtil.areConsecutive(-1, 0) );

    assertFalse( NumberUtil.areConsecutive(0,  0) );
    assertFalse( NumberUtil.areConsecutive(1,  1) );
    assertFalse( NumberUtil.areConsecutive(0,  2) );
    assertFalse( NumberUtil.areConsecutive(1,  3) );
    assertFalse( NumberUtil.areConsecutive(0, -1) );
    assertFalse( NumberUtil.areConsecutive(2,  1) );
    assertFalse( NumberUtil.areConsecutive(1, -2) );
  }

  /**
   * Test consecutive numbers represented as strings.
   */
  public final void testAreConsecutiveStringString() {
    // Consecutive numbers, Roman and Arabic
    assertTrue(  NumberUtil.areConsecutive("0",  "1")   );
    assertTrue(  NumberUtil.areConsecutive("1",  "2")   );
    assertTrue(  NumberUtil.areConsecutive("-1", "0")   );
    assertTrue(  NumberUtil.areConsecutive("VI", "VII") );
    assertTrue(  NumberUtil.areConsecutive("L", "LI")   );
    // Strings are also trimmed before parsing
    assertTrue(  NumberUtil.areConsecutive(" 1 ", " 2 ")   );
    assertTrue(  NumberUtil.areConsecutive(" L ", " LI ")   );

    // Strings which cannot be parsed as ints
    try {
      assertFalse( NumberUtil.areConsecutive("number 1",  "number 2")  );
      fail("Should throw a NumberFormatException.");
    } catch (NumberFormatException e) { /* do nothing */ }
    try {
      assertFalse( NumberUtil.areConsecutive("one",  "two")  );
      fail("Should throw a NumberFormatException.");
    } catch (NumberFormatException e) { /* do nothing */ }

    // Parseable numbers, not consecutive
    assertFalse( NumberUtil.areConsecutive("L", "LII")  );
    assertFalse( NumberUtil.areConsecutive("0", "0")  );
    assertFalse( NumberUtil.areConsecutive("1", "1")  );
    assertFalse( NumberUtil.areConsecutive("0", "2")  );
    assertFalse( NumberUtil.areConsecutive("1", "3")  );
    assertFalse( NumberUtil.areConsecutive("0", "-1") );
    assertFalse( NumberUtil.areConsecutive("2", "1")  );
    assertFalse( NumberUtil.areConsecutive("1", "-2") );
  }

  public final void testAreAlphabeticallyConsecutive() {
    assertTrue(NumberUtil.areAlphabeticallyConsecutive("z", "ba"));
    assertTrue(NumberUtil.areAlphabeticallyConsecutive("aa", "ab"));
    assertTrue(NumberUtil.areAlphabeticallyConsecutive("ab", "ac"));
    assertTrue(NumberUtil.areAlphabeticallyConsecutive("ay", "az"));
    assertTrue(NumberUtil.areAlphabeticallyConsecutive("bz", "ca"));

    assertTrue(NumberUtil.areAlphabeticallyConsecutive("aaa", "aab"));
    assertTrue(NumberUtil.areAlphabeticallyConsecutive("aaz", "aba"));
    assertTrue(NumberUtil.areAlphabeticallyConsecutive("azz", "baa"));
    assertTrue(NumberUtil.areAlphabeticallyConsecutive("zzy", "zzz"));
    assertTrue(NumberUtil.areAlphabeticallyConsecutive("zyz", "zza"));

    // Try mixed case - should be preserved
    assertTrue(NumberUtil.areAlphabeticallyConsecutive("AAA", "AAB"));
    assertTrue(NumberUtil.areAlphabeticallyConsecutive("aaZ", "abA"));
    assertTrue(NumberUtil.areAlphabeticallyConsecutive("aZz", "bAa"));
    assertTrue(NumberUtil.areAlphabeticallyConsecutive("Zzy", "Zzz"));
    assertTrue(NumberUtil.areAlphabeticallyConsecutive("ZyZ", "ZzA"));

    // Not consecutive
    assertFalse(NumberUtil.areAlphabeticallyConsecutive("a", "c"));
    assertFalse(NumberUtil.areAlphabeticallyConsecutive("a", "z"));
    assertFalse(NumberUtil.areAlphabeticallyConsecutive("b", "a"));

    // Changing case means the strings are not alphabetically consecutive
    assertFalse(NumberUtil.areAlphabeticallyConsecutive("AAA", "AAb"));
    assertFalse(NumberUtil.areAlphabeticallyConsecutive("a", "B"));
    assertFalse(NumberUtil.areAlphabeticallyConsecutive("A", "b"));
  }

  public final void testAreEqualValue() {
    assertTrue( NumberUtil.areEqualValue("1", "1") );
    assertTrue( NumberUtil.areEqualValue(" 1 ", " 01 ") );
    assertTrue( NumberUtil.areEqualValue(" 1 ", "I") );
    assertTrue( NumberUtil.areEqualValue("11", " XI ") );
    assertTrue( NumberUtil.areEqualValue("N", "0000") );
    // Strings not both parseable as integers
    assertFalse( NumberUtil.areEqualValue("NO", "YES") );
    assertFalse( NumberUtil.areEqualValue("NO", "NO") );
    assertFalse( NumberUtil.areEqualValue("", "1") );
    assertFalse( NumberUtil.areEqualValue(null, "1") );
    assertFalse( NumberUtil.areEqualValue("one", "1") );
  }

  public final void testAreRangesEqual() {
    assertTrue( NumberUtil.areRangesEqual("1-5", "1 - 5") );
    assertTrue( NumberUtil.areRangesEqual("1-5", "I-V") );
    assertTrue( NumberUtil.areRangesEqual("1-V", "I-5") );
    assertTrue( NumberUtil.areRangesEqual("11", " XI ") );
    assertTrue( NumberUtil.areRangesEqual("N-CXVI", "0000 - 116 ") );
  }

  /**
   * Test normalized Roman and Arabic numbers.
   */
  public void testNormalized() {
	String[] validNormalizedRomanStrings = {
	  "N", "I", "VI", "XIII", "LXXX", "XC",
	  "DLXI", "MCMLXXIV",
	  "(MMMDCCCL)MMCDXXIX",
	  "MMM", "(IV)", "(V)M",
	  "(MMMV)CMXCIX", "(MMMDCCCL)MMCDXXIX",
	  "((MMCXLV)MMCDLXXX)MMMDCXLVII"
	};
    String[] equivalentArabicStrings = {
        "0", "1", "6", "13", "80", "90",
        "561", "1974",
        "3852429",
        "3000", "4000", "6000",
        "3005999", "3852429",
        Integer.toString(Integer.MAX_VALUE)
    };

    // string arrays of roman digits split from normalized roman strings
    String[][] equivalentRomanDigits = {
      {"N"}, {"I"}, {"V","I"}, {"X","I","I","I"}, {"L","X","X","X"}, {"XC"},
      {"D","L","X","I"}, {"M","CM","L","X","X","IV"},
      {"(M)","(M)","(M)","(D)","(C)","(C)","(C)","(L)",
       "M","M","CD","X","X","IX"},
      {"M","M", "M"}, {"(IV)"}, {"(V)","M"},
      {"(M)","(M)","(M)","(V)","CM","XC","IX"},
      {"(M)","(M)","(M)","(D)","(C)","(C)","(C)","(L)",
       "M","M","CD","X","X","IX"},
      {"((M))","((M))","((C))","((XL))","((V))",
       "(M)","(M)","(CD)","(L)","(X)","(X)","(X)",
       "M","M","M","D","C","XL","V","I","I"}
    };

	for (int i = 0; i < validNormalizedRomanStrings.length; i++) {
      String romanValue = validNormalizedRomanStrings[i];
      String arabicValue = equivalentArabicStrings[i];

	  try {
      int intValue = Integer.parseInt(arabicValue);
      // roman value represents a valid Roman number
      assertTrue(NumberUtil.isRomanNumber(romanValue));
      // roman value is normalized
      assertEquals(romanValue, NumberUtil.toRomanNumber(romanValue));
      // roman is normalized
      NumberUtil.parseRomanNumber(romanValue, true);
      // matches roman value
      assertEquals(intValue, NumberUtil.parseInt(romanValue));
      // matches arabic value
      assertEquals(intValue, NumberUtil.parseInt(arabicValue));
      // match split roman string
      assertEquals(equivalentRomanDigits[i],
          NumberUtil.toRomanDigits(romanValue));
      // match split roman string
      assertEquals(equivalentRomanDigits[i],
          NumberUtil.toRomanDigits(arabicValue));
      assertEquals(intValue,
          NumberUtil.parseRomanDigits(equivalentRomanDigits[i]));
    } catch (NumberFormatException ex) {
      fail(ex.getMessage(),ex);
    } catch (IllegalArgumentException ex) {
      fail(ex.getMessage());
    }
	}
  }

  /**
   * Test unnormalized Roman numbers.
   */
  public void testUnnormalized() {
    String[] validUnnormalizedRomanStrings = {
        "VIIII", "LXXXXI", "IM", "DDDDIV", "((I))", "(MMMDCCCLII)CDXXIX",
        "((MMCXLVII)CDLXXXIII)DCXLVII"
    };
    String[] equivalentArabicStrings = {
        "9", "91", "999", "2004", "1000000", "3852429",
        Integer.toString(Integer.MAX_VALUE)
    };

    for (int i = 0; i < validUnnormalizedRomanStrings.length; i++) {
      String romanValue = validUnnormalizedRomanStrings[i];
      String arabicValue = equivalentArabicStrings[i];

      try {
        // roman value represents a valid Roman number
        assertTrue(NumberUtil.isRomanNumber(romanValue));
        // unnormalized roman value matches roman string representation
        assertNotEquals(romanValue, NumberUtil.toRomanNumber(romanValue));
        // roman matches arabic
        assertEquals(NumberUtil.toRomanNumber(romanValue),
            NumberUtil.toRomanNumber(arabicValue));
        // roman matches integer
        assertEquals(NumberUtil.parseInt(romanValue),
            NumberUtil.parseInt(arabicValue));
      } catch (NumberFormatException ex) {
        fail(ex.getMessage());
      } catch (IllegalArgumentException ex) {
        fail(ex.getMessage());
      }

      try {
        // roman is not normalized
        NumberUtil.parseRomanNumber(romanValue, true);
        fail(romanValue + " is unnormalized");
      } catch (NumberFormatException ex) {
      } catch (IllegalArgumentException ex) {
        fail(ex.getMessage());
      }
    }
  }

  /**
   * Test invalid Roman and Arabic numbers.
   */
  public void testInvalid() {
    String[] invalidRomanStrings = {
        "xyzzy", "1234IV", "", "-iv", "100",
        "((MMCXLVII)CDLXXXIII)DCXLVIII"  // too large
    };

    for (String s : invalidRomanStrings) {
      try {
        // String is not a Roman number
        assertFalse(NumberUtil.isRomanNumber(s));
        // String is not a Roman number
        NumberUtil.parseRomanNumber(s);
        fail(s + " is an invaid Roman string");
      } catch (NumberFormatException ex) {
      } catch (IllegalArgumentException ex) {
      }
    }

    String[] invalidArabicStrings = {
        "-1", Long.toString(Integer.MAX_VALUE+1)
    };

    for (String s : invalidArabicStrings) {
      try {
        // String is not a Roman number
        assertFalse(NumberUtil.isRomanNumber(s));
        int intValue = Integer.parseInt(s);
        NumberUtil.toRomanNumber(intValue);
        fail(intValue + " is an invalid integer value");
      } catch (NumberFormatException ex) {
      } catch (IllegalArgumentException ex) {
      }
    }
  }

  /**
   * Test numeric and text ranges
   */
  public void testRange() {
    assertEquals("123", NumberUtil.getRangeStart("123-456"));
    assertEquals("123", NumberUtil.getRangeStart("123"));
    assertEquals("456", NumberUtil.getRangeEnd("123-456"));
    assertEquals("456", NumberUtil.getRangeEnd("456"));
    assertEquals("a-12", NumberUtil.getRangeStart(" a-12 - a-15 "));
    assertEquals("a-15", NumberUtil.getRangeEnd(" a-12 - a-15 "));
    assertEquals("merry-go-round", NumberUtil.getRangeStart("merry-go-round"));
    assertEquals("merry-go-round", NumberUtil.getRangeEnd("merry-go-round"));

    /// test numeric ranges
    assertTrue(NumberUtil.rangeIncludes("123-456", "123"));
    assertTrue(NumberUtil.rangeIncludes("123-456", "CXXIV"));
    assertFalse(NumberUtil.rangeIncludes("123-456", "CXX"));

    // test text ranges
    assertTrue(NumberUtil.rangeIncludes("abc-def", "abc"));
    assertTrue(NumberUtil.rangeIncludes("abc-def", "def"));
    assertTrue(NumberUtil.rangeIncludes("abc-def", "bcdefg"));
    assertTrue(NumberUtil.rangeIncludes("abc", "abc"));

    // Test if rangeIncludes() can be used to establish whether a<=b
    // 0-b is range, a is search term
    assertTrue( NumberUtil.rangeIncludes("0-abc", "abc"));
    assertTrue( NumberUtil.rangeIncludes("0-abc", "ab"));
    assertFalse(NumberUtil.rangeIncludes("0-abc", "abd"));
    assertTrue( NumberUtil.rangeIncludes("0-abc", "0"));
    assertTrue( NumberUtil.rangeIncludes("0-abc", "01"));
    assertTrue( NumberUtil.rangeIncludes("0-abc", "1"));

    // Use compareTo
    assertEquals("abc".compareTo("abc")<=0,
        NumberUtil.rangeIncludes("0-abc", "abc"));
    assertEquals("ab".compareTo("abc")<0,
        NumberUtil.rangeIncludes("0-abc", "ab"));
    assertEquals("abd".compareTo("abc")<0,
        NumberUtil.rangeIncludes("0-abc", "abd"));
    assertEquals("0".compareTo("abc")<0,
        NumberUtil.rangeIncludes("0-abc", "0"));
    assertEquals("01".compareTo("abc")<0,
        NumberUtil.rangeIncludes("0-abc", "01"));
    assertEquals("1".compareTo("abc")<0,
        NumberUtil.rangeIncludes("0-abc", "1"));

    // Test with whitespace
    assertEquals("123", NumberUtil.getRangeStart(" 123 -456"));
    assertEquals("123", NumberUtil.getRangeStart(" 123"));
    assertEquals("456", NumberUtil.getRangeEnd("  123-  456"));
    assertEquals("456", NumberUtil.getRangeEnd("456   "));
    assertTrue(NumberUtil.rangeIncludes("123 - 456", "CXXIV"));
    // Note that the search value is not trimmed, so cannot have initial whitespace
    assertTrue(NumberUtil.rangeIncludes("abc-def", "def  "));
    assertTrue(NumberUtil.rangeIncludes(" abc  -  def ", "bcdefg  "));

    // Test ranges with multiple hyphens
    assertEquals(3, NumberUtil.findRangeHyphen("one-two"));
    assertEquals(5, NumberUtil.findRangeHyphen(" 123 - 789 "));
    assertEquals(5, NumberUtil.findRangeHyphen("0-2-4-6-8-10"));
    assertEquals(5, NumberUtil.findRangeHyphen("a-12 - a-15"));
    assertEquals(0, NumberUtil.findRangeHyphen("-"));
    assertEquals(2, NumberUtil.findRangeHyphen("-----"));
    // Test non-ranges with multiple hyphens
    assertEquals(-1, NumberUtil.findRangeHyphen("1-2-3"));
    assertEquals(-1, NumberUtil.findRangeHyphen("123"));
    assertEquals(-1, NumberUtil.findRangeHyphen("merry-go-round"));
    assertEquals(-1, NumberUtil.findRangeHyphen("----------"));
  }

  public final void testIncrementAlphabeticalString() {
    assertEquals("aab", NumberUtil.incrementBase26String("aaa"));
    assertEquals("aba", NumberUtil.incrementBase26String("aaz"));
    assertEquals("baa", NumberUtil.incrementBase26String("azz"));
    assertEquals("zzz", NumberUtil.incrementBase26String("zzy"));
    assertEquals("zza", NumberUtil.incrementBase26String("zyz"));

    // Try mixed case - should be preserved
    assertEquals("AAB", NumberUtil.incrementBase26String("AAA"));
    assertEquals("abA", NumberUtil.incrementBase26String("aaZ"));
    assertEquals("bAa", NumberUtil.incrementBase26String("aZz"));
    assertEquals("Zzz", NumberUtil.incrementBase26String("Zzy"));
    assertEquals("ZzA", NumberUtil.incrementBase26String("ZyZ"));

    // Try incrementing by different amounts
    assertEquals("aac", NumberUtil.incrementBase26String("aaa", 2));
    assertEquals("abc", NumberUtil.incrementBase26String("aaz", 3));
    assertEquals("baz", NumberUtil.incrementBase26String("azz", 26));
    assertEquals("zzz", NumberUtil.incrementBase26String("zzy", 1));
    assertEquals("zzz", NumberUtil.incrementBase26String("zyz", 26));
    assertEquals("baa", NumberUtil.incrementBase26String("a", 26 * 26));

    // Try decrementing
    assertEquals("aaa", NumberUtil.incrementBase26String("aab", -1));
    assertEquals("aax", NumberUtil.incrementBase26String("aaz", -2));
    assertEquals("axz", NumberUtil.incrementBase26String("azz", -52));
    assertEquals("aza", NumberUtil.incrementBase26String("azz", -25));
    assertEquals("abc", NumberUtil.incrementBase26String("abc", 0));
    assertEquals("yzz", NumberUtil.incrementBase26String("zzz", -(26 * 26)));

    // Try strings at the limit for their length
    assertEquals("ba", NumberUtil.incrementBase26String("z"));
    assertEquals("baa", NumberUtil.incrementBase26String("zz"));
    assertEquals("baaa", NumberUtil.incrementBase26String("zzz"));

    // Try decrementing to negative number
    try {
      NumberUtil.incrementBase26String("a", -1);
      fail("Should throw exception when trying to decrement below 0");
    } catch (NumberFormatException e) {
      /*Expected exception.*/
    }

    // Non-alphabetic chars should cause exception
    for (String s : new String[]{"abc1", "ABC1","£AbC"}) {
      try {
        NumberUtil.incrementBase26String(s);
        fail("Should throw exception with non-alphabetic chars");
      } catch (NumberFormatException e) {
        /*Expected exception.*/
      }
    }
  }

  public final void testBase26() {
    assertEquals("a", NumberUtil.toBase26(0));
    assertEquals("b", NumberUtil.toBase26(1));
    assertEquals("ba", NumberUtil.toBase26(26));
    assertEquals("cb", NumberUtil.toBase26(53));
    assertEquals("baa", NumberUtil.toBase26(26*26));

    assertEquals(0, NumberUtil.fromBase26("a"));
    assertEquals(1, NumberUtil.fromBase26("b"));
    assertEquals(26, NumberUtil.fromBase26("ba"));
    assertEquals(53, NumberUtil.fromBase26("cb"));
    assertEquals(26*26, NumberUtil.fromBase26("baa"));

    // Try converting negative number
    try {
      NumberUtil.toBase26(-1);
      fail("Should throw exception when trying to convert negative number to base-26");
    } catch (NumberFormatException e) {
      /*Expected exception.*/
    }

    // Try converting non-alphabetical number
    try {
      NumberUtil.fromBase26("-abc");
      fail("Should throw exception for non-base-26 string input.");
    } catch (Exception e) {
      /*Expected*/
    }

  }

  public final void testIsContiguousRange() {
    // Empty string does not represent a contiguous range
    assertFalse(NumberUtil.isContiguousRange(""));

    // Single ranges
    assertTrue(NumberUtil.isContiguousRange("1"));
    assertTrue(NumberUtil.isContiguousRange("1-3"));
    assertTrue(NumberUtil.isContiguousRange("I - III"));

    // Consecutive ranges
    assertTrue(NumberUtil.isContiguousRange("1, 2-4, 5-6, 7"));
    assertTrue(NumberUtil.isContiguousRange("10-14, 15-20"));
    assertTrue(NumberUtil.isContiguousRange("s1-s4; s5"));
    // Ranges with Roman tokens and hyphens in range identifiers
    assertFalse(NumberUtil.isContiguousRange("s1-I-s1-IIII; s1-V")); // IIII is not normalised form
    assertTrue(NumberUtil.isContiguousRange("s1-I-s1-IV; s1-V"));
    assertTrue(NumberUtil.isContiguousRange("s1-II - s1-4; s1-V"));
    // Alphabetic ranges, mixed delimiters
    assertTrue(NumberUtil.isContiguousRange("aa,ab,ac-ay;az-bz;ca-no"));
    assertTrue(NumberUtil.isContiguousRange("a1-2,a1-3,a1-4-a1-10"));
    assertTrue(NumberUtil.isContiguousRange("a1-02 , a1-03 ; a1-04  -  a1-10"));

    // Not consecutive ranges
    assertFalse(NumberUtil.isContiguousRange("10-14, 16-20"));
    assertFalse(NumberUtil.isContiguousRange("10-14, 14-20"));
    // Test on Romans
    assertFalse(NumberUtil.isContiguousRange("I, III"));

  }

  public void testRoundToNDecimals() {
    assertEquals(5.0, NumberUtil.roundToNDecimals(5.0, 1));
    assertEquals(5.0, NumberUtil.roundToNDecimals(5.0, 3));
    assertEquals(5.2, NumberUtil.roundToNDecimals(5.25, 1));
    assertEquals(5.3, NumberUtil.roundToNDecimals(5.252, 1));
    assertEquals(5.3, NumberUtil.roundToNDecimals(5.2529999, 1));
    assertEquals(5.25, NumberUtil.roundToNDecimals(5.252, 2));
    assertEquals(5.252, NumberUtil.roundToNDecimals(5.252, 3));
    assertEquals(5.252, NumberUtil.roundToNDecimals(5.252, 4));
  }

  public void testIntPow() {
    assertEquals(0, NumberUtil.intPow(0, 6));
    assertEquals(1, NumberUtil.intPow(10, 0));
    assertEquals(10, NumberUtil.intPow(10, 1));
    assertEquals(100, NumberUtil.intPow(10, 2));
    assertEquals(1000, NumberUtil.intPow(10, 3));
    assertEquals(10000, NumberUtil.intPow(10, 4));
    assertEquals(10000000, (long)Math.pow(10, 7));
    assertEquals(100000000, (long)Math.pow(10, 8));
    assertEquals(425927596977747L, NumberUtil.intPow(123, 7));
    try {
      assertEquals(10000, NumberUtil.intPow(10, -4));
      fail("Negative exponent should throw");
    } catch (IllegalArgumentException e) {
    }
  }

}


text:
@implementation NDPageA

- (void)initialize{
    self.backgroundColor = [UIColor clearColor];
    UIView *blueCover = [[UIView alloc] initWithFrame: self.imageView.frame];
    blueCover.backgroundColor = [UIColor blueColor];
    blueCover.layer.opacity = 0.5f;
    [self addSubview:blueCover];
}

- (id)initWithCoder:(NSCoder *)aCoder{
    if(self = [super initWithCoder:aCoder]){
        [self initialize];
    }
    return self;
}

- (id)initWithFrame:(CGRect)rect{
    if(self = [super initWithFrame:rect]){
        [self initialize];
    }
    return self;
}

- (IBAction)onClickNext:(id)sender {
    [self.delegate goToNextPage];
}

- (IBAction)goToExit:(id)sender {
    [self.delegate goToPreviousPage];
}
@end


text:
AWS::EC2::SecurityGroupEgress
=============================

The `AWS::EC2::SecurityGroupEgress` resource adds an egress rule to an Amazon VPC security group.

Important

Use `AWS::EC2::SecurityGroupIngress` and `AWS::EC2::SecurityGroupEgress` only when necessary, typically to allow security groups to reference each other in ingress and egress rules. Otherwise, use the embedded ingress and egress rules of [AWS::EC2::SecurityGroup](aws-properties-ec2-security-group.html "AWS::EC2::SecurityGroup"). For more information, see [Amazon EC2 Security Groups](http://docs.aws.amazon.com/AWSEC2/latest/UserGuide/using-network-security.html).

Syntax
------

``` {.programlisting}
      {
   "CidrIp" : String,
   "DestinationSecurityGroupId" : String,
   "FromPort" : Integer,
   "GroupId" : String,
   "IpProtocol" : String,
   "ToPort" : Integer
}

```

Properties
----------

For more information about adding egress rules to VPC security groups, go to [AuthorizeSecurityGroupEgress](http://docs.aws.amazon.com/AWSEC2/latest/APIReference/ApiReference-query-AuthorizeSecurityGroupEgress.html) in the *Amazon EC2 API Reference*.

Note

If you change this resource's logical ID, you must also update a property value in order to trigger an update for this resource.

 `CidrIp`
CIDR range.

*Type*: String

*Required*: Conditional. Cannot be used when specifying a destination security group.

*Update requires*: [Replacement](using-cfn-updating-stacks-update-behaviors.html#update-replacement)

 `DestinationSecurityGroupId`
Specifies the group ID of the destination Amazon VPC security group.

*Type*: String

*Required*: Conditional. Cannot be used when specifying a CIDR IP address.

*Update requires*: [Replacement](using-cfn-updating-stacks-update-behaviors.html#update-replacement)

 `FromPort`
Start of port range for the TCP and UDP protocols, or an ICMP type number. If you specify `icmp` for the `IpProtocol` property, you can specify -1 as a wildcard (i.e., any ICMP type number).

*Type*: Integer

*Required*: Yes

*Update requires*: [Replacement](using-cfn-updating-stacks-update-behaviors.html#update-replacement)

 `GroupId`
ID of the Amazon VPC security group to modify. This value can be a reference to an [AWS::EC2::SecurityGroup](aws-properties-ec2-security-group.html "AWS::EC2::SecurityGroup") resource that has a valid VpcId property or the ID of an existing Amazon VPC security group.

*Type*: String

*Required*: Yes

*Update requires*: [Replacement](using-cfn-updating-stacks-update-behaviors.html#update-replacement)

 `IpProtocol`
IP protocol name or number. For valid values, see the IpProtocol parameter in [AuthorizeSecurityGroupIngress](http://docs.aws.amazon.com/AWSEC2/latest/APIReference/ApiReference-query-AuthorizeSecurityGroupIngress.html)

*Type*: String

*Required*: Yes

*Update requires*: [Replacement](using-cfn-updating-stacks-update-behaviors.html#update-replacement)

 `ToPort`
End of port range for the TCP and UDP protocols, or an ICMP code. If you specify `icmp` for the `IpProtocol` property, you can specify -1 as a wildcard (i.e., any ICMP code).

*Type*: Integer

*Required*: Yes

*Update requires*: [Replacement](using-cfn-updating-stacks-update-behaviors.html#update-replacement)

Return Values
-------------

### Ref

When the logical ID of this resource is provided to the `Ref` intrinsic function, `Ref` returns the resource name.

For more information about using the `Ref` function, see [Ref](intrinsic-function-reference-ref.html "Ref").

VPC Security Groups Example
---------------------------

In some cases, you might have an originating (source) security group to which you want to add an outbound rule that allows traffic to a destination (target) security group. The target security group also needs an inbound rule that allows traffic from the source security group. Note that you cannot use the `Ref` function to specify the outbound and inbound rules for each security group. Doing so creates a circular dependency; you cannot have two resources that depend on each other. Instead, use the egress and ingress resources to declare these outbound and inbound rules, as shown in the following template snippet.

``` {.programlisting}
      {
  "AWSTemplateFormatVersion": "2010-09-09",
  "Resources": {
    "SourceSG": {
      "Type": "AWS::EC2::SecurityGroup",
      "Properties": {
        "VpcId" : "vpc-e063f789",
        "GroupDescription": "Sample source security group"
      }
    },
    "TargetSG": {
      "Type": "AWS::EC2::SecurityGroup",
      "Properties": {
        "VpcId" : "vpc-e063f789",
        "GroupDescription": "Sample target security group"
      }
    },
    "OutboundRule": {
      "Type": "AWS::EC2::SecurityGroupEgress",
      "Properties":{
        "IpProtocol": "tcp",
        "FromPort": "0",
        "ToPort": "65535",
        "DestinationSecurityGroupId": {
          "Fn::GetAtt": [
            "TargetSG",
            "GroupId"
          ]
        },
        "GroupId": {
          "Fn::GetAtt": [
            "SourceSG",
            "GroupId"
          ]
        }
      }
    },
    "InboundRule": {
      "Type": "AWS::EC2::SecurityGroupIngress",
      "Properties":{
        "IpProtocol": "tcp",
        "FromPort": "0",
        "ToPort": "65535",
        "SourceSecurityGroupId": {
          "Fn::GetAtt": [
            "SourceSG",
            "GroupId"
          ]
        },
        "GroupId": {
          "Fn::GetAtt": [
            "TargetSG",
            "GroupId"
          ]
        }
      }
    }
  }
}

```


text:
title: "Secure PostgreSQL"
linkTitle: "Secure PostgreSQL"
guide_title: "Secure PostgreSQL"
type: "guide"
description: "Learn how to secure communication between Sensu and the enterprise PostgreSQL event store with certificate authentication."
weight: 65
version: "6.9"
product: "Sensu Go"
platformContent: false
menu:
  sensu-go-6.9:
    parent: deploy-sensu
---

This guide describes how to secure communication between Sensu and the PostgreSQL event store using certificate authentication.
When deploying Sensu for use outside of a local development environment, you should secure it using transport layer security (TLS).

To learn how to secure communications between Sensu and its agents, read [Generate certificates for your Sensu installation][3] and [Secure Sensu][1].

{{% notice note %}}
**NOTE**: This guide describes one option for securing communication between Sensu and PostgreSQL and is intended as a starting point.
Your organization's needs may require a different approach.
{{% /notice  %}}

## Prerequisites

To use this guide, you must have:

- A running Sensu deployment.
- A running PostgreSQL instance that you've configured according to [Scale Sensu Go with Enterprise datastore][4].
The commands in this guide use PostgreSQL version 14.

## Install cfssl

The [CloudFlare cfssl][2] toolkit is released as a collection of command-line tools.

If you followed [Generate certificates for your Sensu installation][3], you already downloaded and installed the Cloudflare cfssl toolkit.
If not, run the following commands:

{{< language-toggle >}}

{{}}
sudo curl -s -L -o /bin/cfssl https://github.com/cloudflare/cfssl/releases/download/v1.6.2/cfssl_1.6.2_linux_amd64
sudo curl -s -L -o /bin/cfssljson https://github.com/cloudflare/cfssl/releases/download/v1.6.2/cfssljson_1.6.2_linux_amd64
sudo curl -s -L -o /bin/cfssl-certinfo https://github.com/cloudflare/cfssl/releases/download/v1.6.2/cfssl-certinfo_1.6.2_linux_amd64
sudo chmod +x /bin/cfssl*
{{}}

{{}}

# Update apt repos
sudo apt-get update

# Install cfssl
sudo apt-get install golang-cfssl

{{}}

{{< /language-toggle >}}

To verify that cfssl is installed, run:

{{}}
cfssl version
{{}}

## Create a Certificate Authority (CA)

Follow these steps to create a CA with cfssl and cfssljson:

1. Create `/etc/sensu/tls` (which does not exist by default):
{{}}
mkdir -p /etc/sensu/tls
{{}}

2. Navigate to the new `/etc/sensu/tls` directory:
{{}}
cd /etc/sensu/tls
{{}}

3. Create the CA:
{{}}
echo '{"CN":"Sensu Test CA","key":{"algo":"rsa","size":2048}}' | cfssl gencert -initca - | cfssljson -bare ca -
{{}}

4. Define signing parameters and profiles:
{{}}
echo '{"signing":{"default":{"expiry":"17520h","usages":["signing","key encipherment","client auth"]},"profiles":{"postgresql":{"usages":["signing","key encipherment","server auth","client auth"],"expiry":"4320h"},"backend":{"usages":["signing","key encipherment","client auth"],"expiry":"4320h"}}}}' > ca-config.json
{{}}
{{% notice note %}}
**NOTE**: We suggest a 6-month expiry duration for security, but you can use any duration you prefer when you define the `expiry` attribute value in the signing parameters.
{{% /notice %}}

You should now have a directory at `/etc/sensu/tls` that contains the following files:

 filename        | description |
-----------------|-------------|
`ca.pem`         | CA root certificate. Required for all systems running the Sensu backend or agent. The agent and backend use `ca.pem` to validate server certificates at connection time. |
`ca-key.pem`     | CA root certificate private key. |
`ca-config.json` | CA signing parameters and profiles. Not used by Sensu. |
`ca.csr`         | Certificate signing request for the CA root certificate. Not used by Sensu. |

## Generate certificate and key for PostgreSQL

Next, generate the certificates you need for PostgreSQL.

This guide assumes your PostgreSQL instance is reachable via a `10.0.0.x` IP address, a fully qualified name (for example, `postgres.example.com`), and an unqualified name (for example, `postgres`):

Unqualified
name | IP address | Fully qualified
domain name
(FQDN) | Additional
names |
-----------------|------------|------------------------------------|----------------------|
postgres         | 10.0.0.43   | postgres.example.com              | localhost, 127.0.0.1 |

The additional names for localhost and 127.0.0.1 are added here for convenience and are not strictly required.

- The values provided for the ADDRESS variable will be used to populate the certificate's SAN records.
For systems with multiple hostnames and IP addresses, add each to the comma-delimited value of the ADDRESS variable.
- The value provided for the NAME variable will be used to populate the certificate's CN record.
It will also be used in the names for the `*.pem` and `*.csr` files.

For example:

{{}}
export ADDRESS=localhost,127.0.0.1,10.0.0.43,postgres,postgres.example.com
export NAME=postgres.example.com
echo '{"CN":"'$NAME'","hosts":[""],"key":{"algo":"rsa","size":2048}}' | cfssl gencert -config=ca-config.json -profile="postgresql" -ca=ca.pem -ca-key=ca-key.pem -hostname="$ADDRESS" - | cfssljson -bare $NAME
{{}}

The `/etc/sensu/tls` directory should now include the following files for your PostgreSQL instance:

 filename        | description |
-----------------|-------------|
`postgres.example.com.pem`     | The certificate that your PostgreSQL instance will use.|
`postgres.example.com-key.pem` | The private key that your PostgreSQL instance will use. |
`postgres.example.com.csr`     | Certificate signing request for the PostgreSQL certificate. Not used. |

## Generate certificate and key for your Sensu backend

Just like the certificate and key for PostgreSQL, you'll need a certificate and key for the Sensu backend.

To generate the backend certificate and key, run:

{{}}
export POSTGRES_USERNAME=sensu
echo '{"CN":"'$POSTGRES_USERNAME'","hosts":[""],"key":{"algo":"rsa","size":2048}}' | cfssl gencert -config=ca-config.json -ca=ca.pem -ca-key=ca-key.pem -hostname="" -profile=backend - | cfssljson -bare $POSTGRES_USERNAME

{{}}

You'll also need to change the ownership of the certificate files to the `sensu` user:

{{}}

chown -R sensu:sensu /etc/sensu/tls

{{}}

You should now have the following files in your `/etc/sensu/tls` directory, which the Sensu backend will use to communicate with PostgreSQL:

 filename        | description |
-----------------|-------------|
`sensu.pem`      | The certificate that your Sensu backend will use.|
`sensu-key.pem`  | The private key that your Sensu backend will use. |
`sensu.csr`      | Certificate signing request for the Sensu backend certificate. Not used. |

Now that you have the required certificates and keys, you can configure Sensu to use certificate authentication with PostgreSQL.

{{% notice warning %}}
**WARNING**: Once you've generated all of your certificates, delete the `ca-key.pem` file from the `/etc/sensu/tls` directory.
The `ca-key.pem` file contains sensitive information and is only needed on your PostgreSQL instance.
{{% /notice %}}

## Configure Sensu to use certificate authentication with PostgreSQL

{{% notice note %}}
**NOTE**: The Sensu backend uses the libpq library to make connections to PostgreSQL.
This library [supports a number of environment variables](https://www.postgresql.org/docs/current/libpq-envars.html) that can be injected into the PostgreSQL data source name (DSN) and are loaded at runtime using the system's environment variable file.
These environment variables allow you to customize the Sensu backend's PostgreSQL DSN construction to suit your needs.
{{% /notice %}}

Working from your Sensu backend, follow these steps to configure Sensu to use certificate authentication with PostgreSQL:

1. Define the environment variables that tell the Sensu backend to use a certificate to authenticate to PostgreSQL:

   {{< language-toggle >}}

  {{}}
echo 'PGUSER=sensu
PGSSLMODE="verify-full"
PGSSLCERT="/etc/sensu/tls/sensu.pem"
PGSSLKEY="/etc/sensu/tls/sensu-key.pem"
PGSSLROOTCERT="/etc/sensu/tls/ca.pem"' | sudo tee /etc/sysconfig/sensu-backend
{{}}

  {{}}
echo 'PGUSER=sensu
PGSSLMODE="verify-full"
PGSSLCERT="/etc/sensu/tls/sensu.pem"
PGSSLKEY="/etc/sensu/tls/sensu-key.pem"
PGSSLROOTCERT="/etc/sensu/tls/ca.pem"' | sudo tee /etc/default/sensu-backend
{{}}

{{< /language-toggle >}}

   Do not restart your backend to load the environment variables yet.

2. Adjust the Sensu datastore connection with sensuctl:

   {{}}

echo 'type: PostgresConfig
api_version: store/v1
metadata:
  name: sensu_postgres
spec:
  dsn: "postgresql://sensu:mypass@postgres.example.com:5432/sensu_events"
  pool_size: 20
  strict: false' | sudo tee postgresconfig.yml

sensuctl create -f postgresconfig.yml

{{}}

   {{% notice note %}}
**NOTE**: Setting `strict: false` in the configuration helps ensure that the Sensu backend will remain active and able to process events even in case of a configuration mistake.
{{% /notice %}}

3. Confirm that the connection to your PostgreSQL instance is healthy:

   {{}}
curl http://localhost:8080/health
{{}}

   The response should be similar to this example, with `true` values for both `Active` and `Healthy`:

   {{}}
{
  "Alarms": null,
  "ClusterHealth": [
    {
      "MemberID": 13217573501179607000,
      "MemberIDHex": "b76e4111d26d35e2",
      "Name": "sensu.example.com",
      "Err": "",
      "Healthy": true
    }
  ],
  "Header": {
    "cluster_id": 11959078708079102000,
    "member_id": 6370351775894128000,
    "raft_term": 4242
  },
  "PostgresHealth": [
    {
      "Name": "sensu_postgres",
      "Active": true,
      "Healthy": true
    }
  ]
}
{{}}

   Now that you've confirmed that the Sensu backend can connect to your PostgreSQL instance, you can configure PostgreSQL to use TLS.

### Configure PostgreSQL to use TLS

To configure your PostgreSQL instance to use TLS:

1. Copy your PostgreSQL certificate files from your Sensu backend.
From the `/etc/sensu/tls` directory, run:

   {{}}
scp postgres.example.com* postgres.example.com:/home/user
scp ca.pem postgres.example.com:/home/user
{{}}

2. From your PostgreSQL instance, create a new directory and move your PostgreSQL certificate files from your Sensu backend:

   {{< language-toggle >}}

   {{}}
sudo mkdir /var/lib/pgsql/14/data/tls
cd /var/lib/pgsql/14/data/tls
cp /home/user/postgres.example.com* /var/lib/pgsql/14/data/tls/
cp /home/user/ca.pem /var/lib/pgsql/14/data/tls/
chown -R postgres:postgres /var/lib/pgsql/14/data
{{}}

   {{}}
sudo mkdir /etc/postgresql/14/main/tls
cd /etc/postgresql/14/main/tls
cp /home/user/postgres.example.com* /etc/postgresql/14/main/tls/
cp /home/user/ca.pem /etc/postgresql/14/main/tls/
chown -R postgres:postgres /etc/postgresql/14/main/
{{}}

{{< /language-toggle >}}

3. Open the PostgreSQL configuration file `postgresql.conf` in your code editor and edit the following lines to enable TLS:

   {{< language-toggle >}}

   {{}}
# vim /var/lib/pgsql/14/data/postgresql.conf

# - SSL -

ssl = on
ssl_ca_file = '/var/lib/pgsql/14/data/tls/ca.pem'
ssl_cert_file = '/var/lib/pgsql/14/data/tls/postgres.example.com.pem'
ssl_key_file = '/var/lib/pgsql/14/data/tls/postgres.example.com-key.pem'
{{}}

   {{}}
# vim /etc/postgresql/14/main/postgresql.conf

# - SSL -

ssl = on
ssl_ca_file = '/etc/postgresql/14/main/tls/ca.pem'
ssl_cert_file = '/etc/postgresql/14/main/tls/postgres.example.com.pem'
ssl_key_file = '/etc/postgresql/14/main/tls/postgres.example.com-key.pem'
{{}}

   {{< / language-toggle >}}

   Save your changes and close the file.

4. Open the `pg_hba.conf` file in your Linux distribution and add the following lines to configure host-based authentication to accept certificates only when accessing the `sensu_events` database:

   {{< language-toggle >}}

   {{}}

# /var/lib/pgsql/14/data/pg_hba.conf (file location)

# Prevent "postgres" superuser login via a certificate
hostssl all             postgres        ::/0                    reject
hostssl all             postgres        0.0.0.0/0               reject

# Rules for Sensu DB connection
hostssl sensu_events    sensu           0.0.0.0/0               cert
{{}}

   {{}}

# /etc/postgresql/14/main/pg_hba.conf (file location)

# Prevent "postgres" superuser login via a certificate
hostssl all             postgres        ::/0                    reject
hostssl all             postgres        0.0.0.0/0               reject

# Rules for Sensu DB connection
hostssl sensu_events    sensu           0.0.0.0/0               cert
{{}}

{{< /language-toggle >}}

   Take care to add the new lines in the positions shown in the following example:

   {{
}}

5. Restart PostgreSQL:

   {{< language-toggle >}}

   {{}}
sudo systemctl restart postgresql-14.service
{{}}

   {{}}
sudo systemctl restart postgresql.service
{{}}

{{< /language-toggle >}}

Now that you've configured PostgreSQL to use TLS and your Sensu user is required to authenticate with a certificate, complete one final step to ensure that the Sensu backend uses the environment variables set earlier in this guide when constructing the PostgreSQL DSN.

### Validate Sensu backend configuration for PostgreSQL

After restarting PostgreSQL, the Sensu user should ***not*** be able to communicate with PostgreSQL because it requires certificate authentication for the `sensu_events` database.
Run:

{{}}
curl http://localhost:8080/health
{{}}

The response should include `false` values for PostgresHealth.Active and PostgresHealth.Healthy:

{{}}
{
  "Alarms": null,
  "ClusterHealth": [
    {
      "MemberID": 13217573501179607000,
      "MemberIDHex": "b76e4111d26d35e2",
      "Name": "sensu.example.com",
      "Err": "",
      "Healthy": true
    }
  ],
  "Header": {
    "cluster_id": 11959078708079102000,
    "member_id": 6370351775894128000,
    "raft_term": 4242
  },
  "PostgresHealth": [
    {
      "Name": "sensu_postgres",
      "Active": false,
      "Healthy": false
    }
  ]
}
{{}}

For Sensu to use certificate authentication, you must restart the backend service to load the environment variables set previously:

{{}}
sudo systemctl restart sensu-backend.service
{{}}

To validate that your Sensu backend can reach PostgreSQL and authenticate after restarting, run the following command:

{{}}
curl http://localhost:8080/health
{{}}

The response should be similar to the following example.
If the `Active` and `Healthy` attributes are not **both** `true`, stop and troubleshoot your connection to PostgreSQL *before* you continue:

{{}}
{
  "Alarms": null,
  "ClusterHealth": [
    {
      "MemberID": 13217573501179607000,
      "MemberIDHex": "b76e4111d26d35e2",
      "Name": "sensu.example.com",
      "Err": "",
      "Healthy": true
    }
  ],
  "Header": {
    "cluster_id": 11959078708079102000,
    "member_id": 6370351775894128000,
    "raft_term": 4242
  },
  "PostgresHealth": [
    {
      "Name": "sensu_postgres",
      "Active": true,
      "Healthy": true
    }
  ]
}
{{}}

### Optional step: Require PostgreSQL as event store

To force Sensu to always use PostgreSQL as the event store instead of falling back to etcd if PostgreSQL becomes unavailable, set `strict: true` in your PostgreSQL configuration file.

**If you prefer to use etcd as a fallback, skip this step.**
Using etcd as a fallback may result in disk quota alarms and etcd unavailability, especially in environments with a large number of events.

To set `strict: true` in your PostgreSQL configuration file, run:

{{}}
echo 'type: PostgresConfig
api_version: store/v1
metadata:
  name: sensu_postgres
spec:
  dsn: "postgresql://postgres.example.com:5432/sensu_events"
  pool_size: 20
  strict: true' | sudo tee postgresconfig.yml

sensuctl create -f postgresconfig.yml
{{}}

Your backend will now use PostgreSQL exclusively for storing events.

To view your PostgresConfig definition and confirm that it is updated, run:

{{}}
sensuctl dump store/v1.PostgresConfig --format yaml
{{}}

[1]: ../secure-sensu
[2]: https://github.com/cloudflare/cfssl
[3]: ../generate-certificates
[4]: ../scale-event-storage


text:
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
const codegen_1 = require("../../compile/codegen");
const util_1 = require("../../compile/util");
const equal_1 = require("../../runtime/equal");
const error = {
    message: "must be equal to constant",
    params: ({ schemaCode }) => codegen_1._ `{allowedValue: ${schemaCode}}`,
};
const def = {
    keyword: "const",
    $data: true,
    error,
    code(cxt) {
        const { gen, data, $data, schemaCode, schema } = cxt;
        if ($data || (schema && typeof schema == "object")) {
            cxt.fail$data(codegen_1._ `!${util_1.useFunc(gen, equal_1.default)}(${data}, ${schemaCode})`);
        }
        else {
            cxt.fail(codegen_1._ `${schema} !== ${data}`);
        }
    },
};
exports.default = def;
//# sourceMappingURL=const.js.map


text:
//
// This file was generated by the JavaTM Architecture for XML Binding(JAXB) Reference Implementation, vhudson-jaxb-ri-2.2-147
// See http://java.sun.com/xml/jaxb
// Any modifications to this file will be lost upon recompilation of the source schema.
// Generated on: 2012.10.07 at 09:30:00 AM EDT
//

package org.restsql.core.sqlresource;

import java.util.ArrayList;
import java.util.List;
import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlType;

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

 * <complexType name="MetaData">
 *   <complexContent>
 *     <restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
 *       <sequence>
 *         <element name="database" type="{http://restsql.org/schema}Database"/>
 *         <element name="table" type="{http://restsql.org/schema}Table" maxOccurs="unbounded"/>
 *       </sequence>
 *     </restriction>
 *   </complexContent>
 * </complexType>
 *

 *
 *
 */
@XmlAccessorType(XmlAccessType.FIELD)
@XmlType(name = "MetaData", propOrder = {
    "database",
    "table"
})
public class MetaData {

    @XmlElement(required = true)
    protected Database database;
    @XmlElement(required = true)
    protected List
 table;

    /**
     * Gets the value of the database property.
     *
     * @return
     *     possible object is
     *     {@link Database }
     *
     */
    public Database getDatabase() {
        return database;
    }

    /**
     * Sets the value of the database property.
     *
     * @param value
     *     allowed object is
     *     {@link Database }
     *
     */
    public void setDatabase(Database value) {
        this.database = value;
    }

    /**
     * Gets the value of the table property.
     *
     *

     * This accessor method returns a reference to the live list,
     * not a snapshot. Therefore any modification you make to the
     * returned list will be present inside the JAXB object.
     * This is why there is not a set method for the table property.
     *
     *

     * For example, to add a new item, do as follows:
     *

     *    getTable().add(newItem);
     *

     *
     *
     *

     * Objects of the following type(s) are allowed in the list
     * {@link Table }
     *
     *
     */
    public List
 getTable() {
        if (table == null) {
            table = new ArrayList
();
        }
        return this.table;
    }

}


text:
import React from 'react';
import PropTypes from 'prop-types';
import { registerComponent, Components } from '../../lib/vulcan-lib';
import Checkbox from '@material-ui/core/Checkbox';

const styles = (theme: ThemeType): JssStyles => ({
  root: {
    marginRight:theme.spacing.unit*3,
    marginTop: 5,
    display: "flex",
    alignItems: "center"
  },
  size: {
    width:36,
    height:0
  },
  inline: {
    display:"inline",
  }
})

const FormComponentCheckbox = ({ classes, label, disabled=false, path, value }, context) => {
  return <div className={classes.root}>
    <Checkbox
      className={classes.size}
      checked={value}
      onChange={(event, checked) => {
        context.updateCurrentValues({
          [path]: checked
        })
      }}
      disabled={disabled}
      disableRipple
    />
    <Components.Typography className={classes.inline} variant="body2" component="label">{label}</Components.Typography>
  </div>
}

(FormComponentCheckbox as any).contextTypes = {
  updateCurrentValues: PropTypes.func,
};

// Replaces FormComponentCheckbox from vulcan-ui-bootstrap
const FormComponentCheckboxComponent = registerComponent("FormComponentCheckbox", FormComponentCheckbox, {styles});

declare global {
  interface ComponentTypes {
    FormComponentCheckbox: typeof FormComponentCheckboxComponent
  }
}


text:
@implementation HzxNavigationController

-(void)viewDidLoad{

    [super viewDidLoad];

}
-(void)pushViewController:(UIViewController *)viewController animated:(BOOL)animated{
    if(self.viewControllers.count > 0)
        viewController.hidesBottomBarWhenPushed = YES;

    [super pushViewController:viewController animated:animated];

}
@end


text:
layout: post
title:  "WebAPI: BatteryManager"
date:   2014-02-05 12:00:00
permalink: /blog/5/
---

In this post were going to explore the (small) [BatteryManager API](https://developer.mozilla.org/en-US/docs/Web/API/BatteryManager).

`BatteryManager` is returned by `navigator.battery`. You can interface with the object in the following ways

* `level`
* `chargingTime`
* `dischargingTime`

The battery manager also dispatches the following events

* `levelchange`
* `chargingchange`
* `chargingtimechange`
* `dischargingtimechange`

You can add an event listener using `addEventListener` interface.

{% highlight javascript %}

function updateStatus() {
    var battery = navigator.battery;
    console.log('Battery: ' + battery.level * 100 + '%');
    console.log('Charge Time: ' + battery.chargingTime);
    console.log('DisCharge Time: ' + battery.dischargingTime);
}

function addBatteryListeners() {
    var battery = navigator.battery;
    battery.addEventListener('levelchange', updateStatus, false);
    battery.addEventListener('chargingchange', updateStatus, false);
    battery.addEventListener('chargingtimechange', updateStatus, false);
    battery.addEventListener('dischargingtimechange', updateStatus, false);
}

addBatteryListeners();
updateStatus();

{% endhighlight %}

Now we can test this...but it's a lot of trouble to create a new application to test this little bit of javascript. Thus, this leads us to an introduction to some of the developer tools.

## Web Developer Tools

The Web Developer Tools for in the Firefox Web browser can be used for any website and for any Firefox OS app.

* Go to the [App Manager](about:app-manager)
* Select the `Apps` Tab on the left hand side
* Select the `Hello, Firefox OS` app from the first post.
* Click on `Debug`

Here there is a couple of different tools at out disposal.

* `Console` - the javascript console
* `Inspector` - inspect HTML elements from the page. Shows the CSS rules applied to the element.
* `Debugger`- used to set breakpoints in javascript code and step through it
* `Style Editor` - CSS editor
* `Profiler` - profile the render and running time of the webpage.
* `Scratchpad` - write javascript code that gets run in the context of the webpage

The one we are interested in is the `Scratchpad`. Just paste the javascript code above, click run, and look at the console! Much simpler than creating another app.


text:
clear
while true; do
echo "==========================================================
       	Digite o número do componente a ser instalado:
		1 - Ubuntu Tweak
		2 - Codeblocks
		3 - Virtualbox
		4 - VLC player
		0 - Sair
==========================================================="
echo -n "->OPÇÃO:  "

read opcao

#verificar se foi digitada uma opcao
if [ -z $opcao ]; then
	echo "ERRO: digite uma opcao"
	exit
fi

case $opcao in
	1)
		sudo add-apt-repository ppa:tualatrix/next &&
		sudo apt-get update &&
		sudo apt-get install ubuntu-tweak;;
	2)
		sudo add-apt-repository ppa:pasgui/ppa &&
		sudo apt-get update &&
		sudo apt-get install wx-common build-essential checkinstall cdbs devscripts dh-make fakeroot libxml-parser-perl check avahi-daemon codeblocks -y;;
	3)
		sudo sh -c 'echo "deb http://download.virtualbox.org/virtualbox/debian trusty contrib" >> /etc/apt/sources.list' &&
		wget -q http://download.virtualbox.org/virtualbox/debian/oracle_vbox.asc -O- | sudo apt-key add - &&
		sudo apt-get update &&
		sudo apt-get install virtualbox;;
	4)
		sudo add-apt-repository ppa:videolan/stable-daily &&
		sudo apt-get update &&
		sudo apt-get install vlc;;
	0)
		echo "Saindo..."
		exit;;
	*)
		echo
		echo "ERRO: opção inválida"
		echo ;;
esac
done


text:
<?php
/**
This is an auto-generated file,
Please DO NOT modify this file directly.
*/
namespace PhpBrew\Topic;

use CLIFramework\Topic\GitHubTopic;

class MigratingFromHomebrewPhpToPhpbrewTopic  extends GitHubTopic {

public $id = 'migrating-from-homebrew-php-to-phpbrew';
public $url = 'https://github.com/phpbrew/phpbrew/wiki/Migrating-from-homebrew-php-to-phpbrew.md';
public $title = 'Migrating from homebrew php to phpbrew';

    public function getRemoteUrl() {
    return $this->remoteUrl;
}

    public function getId() {
    return $this->id;
}

    public function getContent() {
return 'Written by Raphael Stolt [original gist](https://gist.github.com/raphaelstolt/5988689)

## Migrating from [homebrew-php](https://github.com/josegonzalez/homebrew-php) to [phpbrew](https://github.com/c9s/phpbrew)

After installing [phpbrew](https://github.com/c9s/phpbrew#install-phpbrew) it\'s time to install a set of chosen PHP versions. My picks at the time of this writing were:

    sudo phpbrew install php-5.5.0 +default+dbs+mb+apxs2=/usr/sbin/apxs
    sudo phpbrew install php-5.4.17 +default+dbs+mb+apxs2=/usr/sbin/apxs
    sudo phpbrew install php-5.3.27 +default+dbs+mb+apxs2=/usr/sbin/apxs

When not sure where apxs is located on your system, `whereis apxs` is quite chatty.

After the installations succeeded the picked PHP versions should be visible via the `phpbrew list` command.

    phpbrew list
    Installed versions:
      php-5.3.27       (/Users/stolt/.phpbrew/php/php-5.3.27)
                       +default+dbs+mb+apxs2=/usr/sbin/apxs
      php-5.4.17       (/Users/stolt/.phpbrew/php/php-5.4.17)
                       +default+dbs+mb+apxs2=/usr/sbin/apxs
      php-5.5.0        (/Users/stolt/.phpbrew/php/php-5.5.0)
                       +default+dbs+mb+apxs2=/usr/sbin/apxs

Extensions and PEAR packages (i.e. PHPUnit which might also be installed project specific via [Composer](http://getcomposer.org)) for PHP 5.5.0

    phpbrew switch php-5.5.0
    php -v
        PHP 5.5.0 (cli) (built: Jul 12 2013 22:55:52)
        Copyright (c) 1997-2013 The PHP Group
        Zend Engine v2.5.0-dev, Copyright (c) 1998-2013 Zend Technologies

    sudo phpbrew ext install redis && sudo phpbrew ext enable redis
    sudo phpbrew ext install xdebug && sudo phpbrew ext enable xdebug

    php -m | grep xdebug && php -m | grep redis
        xdebug
        redis

    sudo pear config-set auto_discover 1
    sudo pear install pear.phpunit.de/PHPUnit

    which phpunit
        /Users/<username>/.phpbrew/php/php-5.5.0/bin/phpunit

Extensions and PEAR packages for PHP 5.4.17

    phpbrew switch php-5.4.17
    php -v
        PHP 5.4.17 (cli) (built: Jul 12 2013 22:46:15)
        Copyright (c) 1997-2013 The PHP Group
        Zend Engine v2.4.0, Copyright (c) 1998-2013 Zend Technologies

    sudo phpbrew ext install redis && sudo phpbrew ext enable redis
    sudo phpbrew ext install xdebug && sudo phpbrew ext enable xdebug

    php -m | grep xdebug && php -m | grep redis
        xdebug
        redis

    sudo pear config-set auto_discover 1
    sudo pear install pear.phpunit.de/PHPUnit

    which phpunit
        /Users/<username>/.phpbrew/php/php-5.4.17/bin/phpunit

###Troubleshooting when `phpbrew` didn\'t enable the extension
Open the `php.ini` of the specific PHP version (e.g. `/Users/<username>/.phpbrew/php/php-5.5.0/etc/php.ini`) and add the following lines manually to it.

    extension_dir = "/Users/<username>/.phpbrew/php/php-5.5.0/lib/php/extensions/no-debug-non-zts-20121212"

    extension=redis.so

    zend_extension="/Users/<username>/.phpbrew/php/php-5.5.0/lib/php/extensions/no-debug-non-zts-20121212/xdebug.so"

Check extension availability with `php -m`.

###Enable autocompletion for `zsh`
This comes in quite handy when switching the PHP versions, without having to do a `phpbrew list` lookup to get the actual installed ones, as the installed ones will get suggested via autocompletion.

    cd /usr/local/share/zsh-completions
    curl -O https://raw.github.com/c9s/phpbrew/master/completion/zsh/_phpbrew
    source ~/.zshrc

###Drawback of `phpbrew switch <php-version>`
The activation of the apxs PHP module via the `LoadModule` statement has to be done manually in `/private/etc/apache2/httpd.conf`, and afterwards the Apache webserver needs to be restarted.

    LoadModule php5_module libexec/apache2/libphp5.5.0.so
    #LoadModule php5_module libexec/apache2/libphp5.4.17.so
    #LoadModule php5_module libexec/apache2/libphp5.3.27.so

###Removal of the former homebrew-php installation

Remove the PHP related brew formulars and taps™.

    sudo brew uninstall php54 php54-intl php54-redis php54-xdebug

    brew untap homebrew/dupes
    brew untap josegonzalez/homebrew-php

Remove the possible PATH expansion from `~/.bash_profile` or `~/.zshrc`.

    export PATH="$(brew --prefix php54)"/bin:$PATH

Remove the `LoadModule` statement from `/private/etc/apache2/httpd.conf`.

    LoadModule php5_module /usr/local/Cellar/php54/5.4.16/libexec/apache2/libphp5.so';
}

}


text:
package xyz.jadonfowler.minekraft.render;

public class Font {

    private Texture fontTexture;

    public Texture loadFont(String location) {
        return null;
    }
}