text:
/*!
 * @file
 * @brief Header for the Argon RTOS wrapper classes.
 * @ingroup ar
 */

#if !defined(_AR_CLASSES_H_)
#define _AR_CLASSES_H_

#include "ar_kernel.h"
#include <string.h>

#if defined(__cplusplus)

//! @brief The Argon RTOS namespace.
namespace Ar {

//------------------------------------------------------------------------------
// Classes
//------------------------------------------------------------------------------

/*!
 * @brief Preemptive thread class.
 *
 * @ingroup ar_thread
 *
 * This thread class implements a preemptive thread with variable priority.
 *
 * Threads may be allocated either globally or with the new operator. You can also allocate a
 * thread locally, but you must be careful to keep the stack valid as long as the thread is running.
 * There are two options for initialization. Either use one of the non-default constructors, or
 * use the default constructor and call an init() method at some later point. Both the constructors
 * and init methods take the same arguments. They accept a name, entry point, stack, and priority.
 *
 * The entry point can be a global or static function that matches the #ar_thread_entry_t
 * prototype. Alternatively, there are constructor and init() variants that let you use a member
 * function of a specific object as the entry point.
 *
 * The init() method leaves the new thread suspended. To make the new thread eligible to
 * run you must call the resume() method on it.
 */
class Thread : public _ar_thread
{
public:
    //! @brief Default constructor.
    Thread() {}

    //! @brief Constructor.
    //!
    //! @param name Name of the thread. If NULL, the thread's name is set to an empty string.
    //! @param entry Thread entry point taking one parameter and returning void.
    //! @param param Arbitrary pointer-sized value passed as the single parameter to the thread
    //!     entry point.
    //! @param stack Pointer to the start of the thread's stack. This should be the stack's bottom,
    //!     not it's top. If this parameter is NULL, the stack will be dynamically allocated.
    //! @param stackSize Number of bytes of stack space allocated to the thread. This value is
    //!     added to @a stack to get the initial top of stack address.
    //! @param priority Thread priority. The accepted range is 1 through 255. Priority 0 is
    //!     reserved for the idle thread.
    //! @param startImmediately Whether the new thread will start to run automatically. If false, the
    //!     thread will be created in a suspended state. The constants #kArStartThread and
    //!     #kArSuspendThread can be used to better document this parameter value.
    Thread(const char * name, ar_thread_entry_t entry, void * param, void * stack, unsigned stackSize, uint8_t priority, bool startImmediately=true)
    {
        init(name, entry, param, stack, stackSize, priority, startImmediately);
    }

    //! @brief Constructor to set the thread entry to a member function.
    //!
    //! @param name Name of the thread. If NULL, the thread's name is set to an empty string.
    //! @param object Pointer to an instance of class T upon which the @a entry member function
    //!     will be invoked when the thread is started.
    //! @param entry Member function of class T that will be used as the thread's entry point.
    //!     The member function must take no parameters and return void.
    //! @param stack Pointer to the start of the thread's stack. This should be the stack's bottom,
    //!     not it's top. If this parameter is NULL, the stack will be dynamically allocated.
    //! @param stackSize Number of bytes of stack space allocated to the thread. This value is
    //!     added to @a stack to get the initial top of stack address.
    //! @param priority Thread priority. The accepted range is 1 through 255. Priority 0 is
    //!     reserved for the idle thread.
    //! @param startImmediately Whether the new thread will start to run automatically. If false, the
    //!     thread will be created in a suspended state. The constants #kArStartThread and
    //!     #kArSuspendThread can be used to better document this parameter value.
    template <class T>
    Thread(const char * name, T * object, void (T::*entry)(), void * stack, unsigned stackSize, uint8_t priority, bool startImmediately=true)
    {
        init<T>(name, object, entry, stack, stackSize, priority, startImmediately);
    }

    //! @brief Constructor to dynamically allocate the stack.
    //!
    //! @param name Name of the thread. If NULL, the thread's name is set to an empty string.
    //! @param entry Thread entry point taking one parameter and returning void.
    //! @param param Arbitrary pointer-sized value passed as the single parameter to the thread
    //!     entry point.
    //! @param stackSize Number of bytes of stack space to allocate via <tt>new</tt> to the thread.
    //! @param priority Thread priority. The accepted range is 1 through 255. Priority 0 is
    //!     reserved for the idle thread.
    //! @param startImmediately Whether the new thread will start to run automatically. If false, the
    //!     thread will be created in a suspended state. The constants #kArStartThread and
    //!     #kArSuspendThread can be used to better document this parameter value.
    Thread(const char * name, ar_thread_entry_t entry, void * param, unsigned stackSize, uint8_t priority, bool startImmediately=true)
    {
        init(name, entry, param, NULL, stackSize, priority, startImmediately);
    }

    //! @brief Constructor to set the thread entry to a member function, using a dynamic stack.
    //!
    //! @param name Name of the thread. If NULL, the thread's name is set to an empty string.
    //! @param object Pointer to an instance of class T upon which the @a entry member function
    //!     will be invoked when the thread is started.
    //! @param entry Member function of class T that will be used as the thread's entry point.
    //!     The member function must take no parameters and return void.
    //! @param stackSize Number of bytes of stack space to allocate via <tt>new</tt> to the thread.
    //! @param priority Thread priority. The accepted range is 1 through 255. Priority 0 is
    //!     reserved for the idle thread.
    //! @param startImmediately Whether the new thread will start to run automatically. If false, the
    //!     thread will be created in a suspended state. The constants #kArStartThread and
    //!     #kArSuspendThread can be used to better document this parameter value.
    template <class T>
    Thread(const char * name, T * object, void (T::*entry)(), unsigned stackSize, uint8_t priority, bool startImmediately=true)
    {
        init<T>(name, object, entry, NULL, stackSize, priority, startImmediately);
    }

    //! @brief Destructor.
    virtual ~Thread();

    //! @name Thread init and cleanup
    //@{
    //! @brief Base initialiser.
    //!
    //! The thread is in suspended state when this method exits. To make it eligible for
    //! execution, call the resume() method.
    //!
    //! @param name Name of the thread. If NULL, the thread's name is set to an empty string.
    //! @param entry Thread entry point taking one parameter and returning void.
    //! @param param Arbitrary pointer-sized value passed as the single parameter to the thread
    //!     entry point.
    //! @param stack Pointer to the start of the thread's stack. This should be the stack's bottom,
    //!     not it's top. If this parameter is NULL, the stack will be dynamically allocated.
    //! @param stackSize Number of bytes of stack space allocated to the thread. This value is
    //!     added to @a stack to get the initial top of stack address.
    //! @param priority Thread priority. The accepted range is 1 through 255. Priority 0 is
    //!     reserved for the idle thread.
    //! @param startImmediately Whether the new thread will start to run automatically. If false, the
    //!     thread will be created in a suspended state. The constants #kArStartThread and
    //!     #kArSuspendThread can be used to better document this parameter value.
    //!
    //! @retval #kArSuccess The thread was initialised without error.
    //! @retval #kArOutOfMemoryError Failed to dynamically allocate the stack.
    ar_status_t init(const char * name, ar_thread_entry_t entry, void * param, void * stack, unsigned stackSize, uint8_t priority, bool startImmediately=true);

    //! @brief Initializer to set the thread entry to a member function.
    //!
    //! @param name Name of the thread. If NULL, the thread's name is set to an empty string.
    //! @param object Pointer to an instance of class T upon which the @a entry member function
    //!     will be invoked when the thread is started.
    //! @param entry Member function of class T that will be used as the thread's entry point.
    //!     The member function must take no parameters and return void.
    //! @param stack Pointer to the start of the thread's stack. This should be the stack's bottom,
    //!     not it's top. If this parameter is NULL, the stack will be dynamically allocated.
    //! @param stackSize Number of bytes of stack space allocated to the thread. This value is
    //!     added to @a stack to get the initial top of stack address.
    //! @param priority Thread priority. The accepted range is 1 through 255. Priority 0 is
    //!     reserved for the idle thread.
    //! @param startImmediately Whether the new thread will start to run automatically. If false, the
    //!     thread will be created in a suspended state. The constants #kArStartThread and
    //!     #kArSuspendThread can be used to better document this parameter value.
    //!
    //! @retval #kArSuccess The thread was initialised without error.
    //! @retval #kArOutOfMemoryError Failed to dynamically allocate the stack.
    template <class T>
    ar_status_t init(const char * name, T * object, void (T::*entry)(), void * stack, unsigned stackSize, uint8_t priority, bool startImmediately=true)
    {
        return initForMemberFunction(name, object, member_thread_entry<T>, &entry, sizeof(entry), stack, stackSize, priority, startImmediately);
    }
    //@}

    //! @brief Get the thread's name.
    const char * getName() const { return m_name; }

    //! @name Thread state
    //!
    //! Control of and access to the thread state.
    //@{
    //! @brief Put thread in suspended state.
    //!
    //! If this method is called from the current thread then the scheduler is entered immediately
    //! after putting the thread on the suspended list. Calling suspend() on another thread will not
    //! cause the scheduler to switch threads.
    //!
    //! Does not enter the scheduler if Ar is not running. Does nothing if the thread is already
    //! suspended.
    //!
    //! @todo Deal with all thread states properly.
    void suspend() { ar_thread_suspend(this); }

    //! @brief Make the thread eligible for execution.
    //!
    //! If the thread being resumed has a higher priority than that of the current thread, the
    //! scheduler is called to immediately switch threads. In this case the thread being resumed
    //! will always become the new current thread. This is because the highest priority thread is
    //! always guaranteed to be running, meaning the calling thread was the previous highest
    //! priority thread.
    //!
    //! Does not enter the scheduler if Ar is not running. Does nothing if the thread is already on
    //! the ready list.
    //!
    //! @todo Deal with all thread states properly.
    void resume() { ar_thread_resume(this); }

    //! @brief Return the current state of the thread.
    ar_thread_state_t getState() const { return m_state; }

    //! @brief Put the current thread to sleep for a certain amount of time.
    //!
    //! Does nothing if Ar is not running.
    //!
    //! A sleeping thread can be woken early by calling ar_thread_resume().
    //!
    //! @param milliseconds The number of milliseconds to sleep the calling thread. A sleep time
    //!     of 0 is ignored. If the sleep time is shorter than the scheduler quanta, then the thread
    //!     will not actually sleep. If #kArInfiniteTimeout is passed for the sleep time, the thread
    //!     will simply be suspended.
    static void sleep(unsigned milliseconds) { ar_thread_sleep(milliseconds); }

    //! @brief Put the current thread to sleep until a specific time.
    //!
    //! Does nothing if Ar is not running.
    //!
    //! A sleeping thread can be woken early by calling ar_thread_resume().
    //!
    //! @param wakeup The wakeup time in milliseconds. If the time is not in the future, i.e., less than
    //!  or equal to the current value returned by ar_get_millisecond_count(), then the sleep request is
    //!  ignored.
    static void sleepUntil(unsigned wakeup) { ar_thread_sleep_until(wakeup); }
    //@}

    //! @name Thread priority
    //!
    //! Accessors for the thread's priority.
    //@{
    //! @brief Return the thread's current priority.
    uint8_t getPriority() const { return m_priority; }

    //! @brief Change the thread's priority.
    //!
    //! The scheduler is invoked after the priority is set so that the current thread can be changed
    //! to the one with the highest priority. The scheduler is invoked even if there is no new
    //! highest priority thread. In this case, control may switch to the next thread with the same
    //! priority, assuming there is one.
    //!
    //! Does not enter the scheduler if Ar is not running.
    //!
    //! @param priority Thread priority level from 1 to 255, where lower numbers have a lower
    //!     priority. Priority number 0 is not allowed because it is reserved for the idle thread.
    //!
    //! @retval #kArSuccess
    //! @retval #kArInvalidPriorityError
    ar_status_t setPriority(uint8_t priority) { return ar_thread_set_priority(this, priority); }
    //@}

    //! @name Info
    //@{
    //! @brief Get the thread's system load.
    uint32_t getLoad() { return ar_thread_get_load(this); }

    //! @brief Get the thread's maximum stack usage.
    uint32_t getStackUsed() { return ar_thread_get_stack_used(this); }
    //@}

    //! @name Accessors
    //!
    //! Static members to get system-wide information.
    //@{
    //! @brief Returns the currently running thread object.
    static Thread * getCurrent() { return static_cast<Thread *>(ar_thread_get_current()); }
    //@}

protected:

    uint8_t * m_allocatedStack; //!< Dynamically allocated stack.
    ar_thread_entry_t m_userEntry;  //!< User-specified thread entry point function.

    //! @brief Virtual thread entry point.
    //!
    //! This is the method that subclasses should override.
    virtual void threadEntry(void * param);

    //! @brief Static thread entry callback to invoke the virtual method.
    static void thread_entry(void * param);

    //! @brief Template function to invoke a thread entry point that is a member function.
    template <class T>
    static void member_thread_entry(void * param)
    {
        Thread * thread = getCurrent();
        T * obj = static_cast<T *>(param);
        void (T::*member)(void);
        uint32_t * storage = thread->m_stackBottom + 1; // Add 1 to skip over check value.
        memcpy((char*)&member, storage, sizeof(member));
        (obj->*member)();
    }

    //! @brief Special init method to deal with member functions.
    ar_status_t initForMemberFunction(const char * name, void * object, ar_thread_entry_t entry, void * memberPointer, uint32_t memberPointerSize, void * stack, unsigned stackSize, uint8_t priority, bool startImmediately);

private:
    //! @brief The copy constructor is disabled for thread objects.
    Thread(const Thread & other);

    //! @brief Disable assignment operator.
    Thread& operator=(const Thread & other);
};

/*!
 * @brief Template to create a thread and its stack.
 *
 * @ingroup ar_thread
 */
template <uint32_t S>
class ThreadWithStack : public Thread
{
public:
    //! @brief Default constructor.
    ThreadWithStack() {}

    //! @brief Constructor to use a normal function as entry poin.
    ThreadWithStack(const char * name, ar_thread_entry_t entry, void * param, uint8_t priority, bool startImmediately=true)
    {
        Thread::init(name, entry, param, m_stack, S, priority, startImmediately);
    }

    //! @brief Constructor to set the thread entry to a member function.
    template <class T>
    ThreadWithStack(const char * name, T * object, void (T::*entry)(), uint8_t priority, bool startImmediately=true)
    {
        Thread::init<T>(name, object, entry, m_stack, S, priority, startImmediately);
    }

    //! @brief Initializer to use a normal function as entry point.
    ar_status_t init(const char * name, ar_thread_entry_t entry, void * param, uint8_t priority, bool startImmediately=true)
    {
        return Thread::init(name, entry, param, m_stack, S, priority, startImmediately);
    }

    //! @brief Initializer to set the thread entry to a member function.
    template <class T>
    ar_status_t init(const char * name, T * object, void (T::*entry)(), uint8_t priority, bool startImmediately=true)
    {
        return Thread::init<T>(name, object, entry, m_stack, S, priority, startImmediately);
    }

protected:
    uint8_t m_stack[S]; //!< Stack space for the thread.

private:
    //! @brief The copy constructor is disabled for thread objects.
    ThreadWithStack(const ThreadWithStack<S> & other);

    //! @brief Disable assignment operator.
    ThreadWithStack& operator=(const ThreadWithStack<S> & other);
};

/*!
 * @brief Counting semaphore class.
 *
 * @ingroup ar_sem
 *
 * @see Semaphore::Guard
 */
class Semaphore : public _ar_semaphore
{
public:
    //! @brief Default constructor.
    Semaphore() {}

    //! @brief Constructor.
    Semaphore(const char * name, unsigned count=1)
    {
        init(name, count);
    }

    //! @brief Initialiser.
    //!
    //! @param name Pass a name for the semaphore. If NULL is passed the name will be set to an
    //!     empty string.
    //! @param count The initial semaphore count. Setting this value to 0 will cause the first call
    //!     to get() to block until put() is called. A value of 1 or greater will allow that many
    //!     calls to get() to succeed.
    //!
    //! @retval #kArSuccess Semaphore initialised successfully.
    ar_status_t init(const char * name, unsigned count=1) { return ar_semaphore_create(this, name, count); }

    //! @brief Destructor.
    //!
    //! Any threads on the blocked list will be unblocked immediately. Their return status from the
    //! get() method will be #kArObjectDeletedError.
    ~Semaphore() { ar_semaphore_delete(this); }

    //! @brief Get the semaphore's name.
    const char * getName() const { return m_name; }

    //! @brief Acquire the semaphore.
    //!
    //! The semaphore count is decremented. If the count is 0 upon entering this method then the
    //! caller thread is blocked until the count reaches 1. Threads are unblocked in the order in
    //! which they were blocked. Priority is not taken into consideration, so priority inversions
    //! are possible.
    //!
    //! @note This function may be called from interrupt context only if the timeout parameter is
    //!     set to #kArNoTimeout (or 0).
    //!
    //! @param timeout The maximum number of milliseconds that the caller is willing to wait in a
    //!     blocked state before the semaphore can be obtained. If this value is 0, or #kArNoTimeout,
    //!     then this method will return immediately if the semaphore cannot be obtained. Setting
    //!     the timeout to #kArInfiniteTimeout will cause the thread to wait forever for a chance to
    //!     get the semaphore.
    //!
    //! @retval #kArSuccess The semaphore was obtained without error.
    //! @retval #kArTimeoutError The specified amount of time has elapsed before the semaphore could be
    //!     obtained.
    //! @retval #kArObjectDeletedError Another thread deleted the semaphore while the caller was
    //!     blocked on it.
    //! @retval #kArNotFromInterruptError A non-zero timeout is not alllowed from the interrupt
    //!     context.
    ar_status_t get(uint32_t timeout=kArInfiniteTimeout) { return ar_semaphore_get(this, timeout); }

    //! @brief Release the semaphore.
    //!
    //! The semaphore count is incremented.
    //!
    //! @note This call is safe from interrupt context.
    //!
    //! @retval #kArSuccess The semaphore was released without error.
    ar_status_t put() { return ar_semaphore_put(this); }

    //! @brief Returns the current semaphore count.
    unsigned getCount() const { return m_count; }

private:
    //! @brief Disable copy constructor.
    Semaphore(const Semaphore & other);

    //! @brief Disable assignment operator.
    Semaphore& operator=(const Semaphore & other);
};

/*!
 * @brief Mutex object.
 *
 * @ingroup ar_mutex
 *
 * Very similar to a binary semaphore, except that a single thread can lock the mutex multiple times
 * without deadlocking. In this case, the number of calls to get() and put() must be matched.
 *
 * Another difference from semaphores is that mutexes support priority inheritance. If a high-
 * priority thread blocks on a mutex held by a lower-priority thread, the thread holding the mutex
 * will have its priority temporarily raised to the priority of the thread waiting on the mutex.
 *
 * @see Mutex::Guard
 */
class Mutex : public _ar_mutex
{
public:
    //! @brief Default constructor.
    Mutex() {}

    //! @brief Constructor.
    Mutex(const char * name)
    {
        init(name);
    }

    //! @brief Initialiser.
    //!
    //! The mutex starts out unlocked.
    //!
    //! @param name The name of the mutex.
    //!
    //! @retval SUCCCESS
    ar_status_t init(const char * name) { return ar_mutex_create(this, name); }

    //! @brief Cleanup.
    ~Mutex() { ar_mutex_delete(this); }

    //! @brief Get the mutex's name.
    const char * getName() const { return m_name; }

    //! @brief Lock the mutex.
    //!
    //! If the thread that already owns the mutex calls get() more than once, a count is incremented
    //! rather than attempting to decrement the underlying semaphore again. The converse is true for
    //! put(), thus allowing a thread to lock a mutex any number of times as long as there are
    //! matching get() and put() calls.
    //!
    //! @param timeout The maximum number of milliseconds that the caller is willing to wait in a
    //!     blocked state before the semaphore can be obtained. If this value is 0, or #kArNoTimeout,
    //!     then this method will return immediately if the lock cannot be obtained. Setting
    //!     the timeout to #kArInfiniteTimeout will cause the thread to wait forever for a chance to
    //!     get the lock.
    //!
    //! @retval #kArSuccess The mutex was obtained without error.
    //! @retval #kArTimeoutError The specified amount of time has elapsed before the mutex could be
    //!     obtained.
    //! @retval #kArObjectDeletedError Another thread deleted the semaphore while the caller was
    //!     blocked on it.
    ar_status_t get(uint32_t timeout=kArInfiniteTimeout) { return ar_mutex_get(this, timeout); }

    //! @brief Unlock the mutex.
    //!
    //! Only the owning thread is allowed to unlock the mutex. If the owning thread has called get()
    //! multiple times, it must also call put() the same number of time before the underlying
    //! semaphore is actually released. It is illegal to call put() when the mutex is not owned by
    //! the calling thread.
    //!
    //! @retval #kArAlreadyUnlockedError The mutex is not locked.
    //! @retval #kArNotOwnerError The caller is not the thread that owns the mutex.
    ar_status_t put() { return ar_mutex_put(this); }

    //! @brief Returns the current owning thread, if there is one.
    ar_thread_t * getOwner() { return (ar_thread_t *)m_owner; }

    //! @brief Returns whether the mutex is currently locked.
    //!
    //! @retval true The mutex is locked.
    //! @retval false The mutex is unlocked.
    bool isLocked() { return ar_mutex_is_locked(this); }

    /*!
     * @brief Utility class to automatically get and put a mutex.
     *
     * @ingroup ar_mutex
     *
     * This class is intended to be stack allocated. It gets and holds a mutex for the
     * duration of the scope in which it is declared. Once it goes out of scope, the destructor
     * automatically puts the lock.
     */
    class Guard
    {
    public:
        //! @brief Constructor which gets the mutex.
        Guard(Mutex & mutex)
        :   m_mutex(mutex)
        {
            m_mutex.get(kArInfiniteTimeout);
        }

        //! @brief Destructor that puts the mutex.
        ~Guard()
        {
            m_mutex.put();
        }

    protected:
        Mutex & m_mutex;  //!< The mutex to hold.
    };

private:
    //! @brief Disable copy constructor.
    Mutex(const Mutex & other);

    //! @brief Disable assignment operator.
    Mutex& operator=(const Mutex & other);
};

/*!
 * @brief Channel.
 *
 * @ingroup ar_chan
 */
class Channel : public _ar_channel
{
public:
    //! @brief Default constructor.
    Channel() {}

    //! @brief Constructor.
    Channel(const char * name, uint32_t width=0) { init(name, width); }

    //! @brief Destructor.
    ~Channel() { ar_channel_delete(this); }

    //! @brief Channel initialiser.
    ar_status_t init(const char * name, uint32_t width=0) { return ar_channel_create(this, name, width); }

    //! @brief Send to channel.
    ar_status_t send(const void * value, uint32_t timeout=kArInfiniteTimeout) { return ar_channel_send(this, value, timeout); }

    //! @brief Receive from channel.
    ar_status_t receive(void * value, uint32_t timeout=kArInfiniteTimeout) { return ar_channel_receive(this, value, timeout); }

private:
    //! @brief Disable copy constructor.
    Channel(const Channel & other);

    //! @brief Disable assignment operator.
    Channel& operator=(const Channel & other);
};

/*!
 * @brief Typed channel.
 *
 * @ingroup ar_chan
 */
template <typename T>
class TypedChannel : public Channel
{
public:
    //! @brief Default constructor.
    TypedChannel() {}

    //! @brief Constructor.
    TypedChannel(const char * name) : Channel(name, sizeof(T)) {}

    //! @brief Channel initialiser.
    ar_status_t init(const char * name) { return Channel::init(name, sizeof(T)); }

    //! @brief Send to channel.
    ar_status_t send(const T & value, uint32_t timeout=kArInfiniteTimeout)
    {
        return Channel::send(&value, timeout);
    }

    //! @brief Receive from channel.
    T receive(uint32_t timeout=kArInfiniteTimeout)
    {
        T temp;
        Channel::receive(&temp, timeout);
        return temp;
    }

    //! @brief Receive from channel.
    ar_status_t receive(T & value, uint32_t timeout=kArInfiniteTimeout)
    {
        return Channel::receive(&value, timeout);
    }

    //! @brief Receive from channel.
    friend T& operator <<= (T& lhs, TypedChannel<T>& rhs)
    {
        lhs = rhs.receive();
        return lhs;
    }

    //! @brief Send to channel.
    friend T& operator >> (T& lhs, TypedChannel<T>& rhs)
    {
        rhs.send(lhs);
        return lhs;
    }

private:
    //! @brief Disable copy constructor.
    TypedChannel(const TypedChannel<T> & other);

    //! @brief Disable assignment operator.
    TypedChannel& operator=(const TypedChannel<T> & other);
};

/*!
 * @brief A blocking queue for inter-thread messaging.
 *
 * @ingroup ar_queue
 */
class Queue : public _ar_queue
{
public:
    //! @brief Default constructor.
    Queue() {}

    //! @brief Constructor.
    Queue(const char * name, void * storage, unsigned elementSize, unsigned capacity)
    {
        init(name, storage, elementSize, capacity);
    }

    //! @brief Queue initialiser.
    //!
    //! @param name The new queue's name.
    //! @param storage Pointer to a buffer used to store queue elements. The buffer must be at least
    //!     @a elementSize * @a capacity bytes big.
    //! @param elementSize Size in bytes of each element in the queue.
    //! @param capacity The number of elements that the buffer pointed to by @a storage will hold.
    //!
    //! @retval #kArSuccess The queue was initialised.
    ar_status_t init(const char * name, void * storage, unsigned elementSize, unsigned capacity)
    {
        return ar_queue_create(this, name, storage, elementSize, capacity);
    }

    //! @brief Queue cleanup.
    ~Queue() { ar_queue_delete(this); }

    //! @brief Get the queue's name.
    const char * getName() const { return m_name; }

    //! @brief Add an item to the queue.
    //!
    //! The caller will block if the queue is full.
    //!
    //! @param element Pointer to the element to post to the queue. The element size was specified
    //!     in the init() call.
    //! @param timeout The maximum number of milliseconds that the caller is willing to wait in a
    //!     blocked state before the element can be sent. If this value is 0, or #kArNoTimeout, then
    //!     this method will return immediately if the queue is full. Setting the timeout to
    //!     #kArInfiniteTimeout will cause the thread to wait forever for a chance to send.
    //!
    //! @retval #kArSuccess
    //! @retval #kArQueueFullError
    ar_status_t send(const void * element, uint32_t timeout=kArInfiniteTimeout) { return ar_queue_send(this, element, timeout); }

    //! @brief Remove an item from the queue.
    //!
    //! @param[out] element
    //! @param timeout The maximum number of milliseconds that the caller is willing to wait in a
    //!     blocked state before an element is received. If this value is 0, or #kArNoTimeout, then
    //!     this method will return immediately if the queue is empty. Setting the timeout to
    //!     #kArInfiniteTimeout will cause the thread to wait forever for receive an element.
    //!
    //! @retval #kArSuccess
    //! @retval #kArQueueEmptyError
    ar_status_t receive(void * element, uint32_t timeout=kArInfiniteTimeout) { return ar_queue_receive(this, element, timeout); }

    //! @brief Returns whether the queue is currently empty.
    bool isEmpty() const { return m_count == 0; }

    //! @brief Returns the current number of elements in the queue.
    unsigned getCount() const { return m_count; }

private:
    //! @brief Disable copy constructor.
    Queue(const Queue & other);

    //! @brief Disable assignment operator.
    Queue& operator=(const Queue & other);
};

/*!
 * @brief Template class to help statically allocate a Queue.
 *
 * @ingroup ar_queue
 *
 * This template class helps create a Queue instance by defining a static array of queue elements.
 * The array length is one of the template parameters.
 *
 * Example of creating a queue and adding an element:
 * @code
 *      // MyQueueType holds up to five uint32_t elements.
 *      typedef StaticQueue<uint32_t, 5> MyQueueType;
 *
 *      MyQueueType q; // Can statically allocate MyQueueType!
 *      q.init("my queue");
 *
 *      uint32_t element = 512;
 *      q.send(element);
 *
 *      q.send(1024);
 *
 *      ar_status_t s;
 *
 *      s = q.receive(&element);
 *
 *      element = q.receive(&s);
 * @endcode
 *
 * @param T The queue element type.
 * @param N Maximum number of elements the queue will hold.
 */
template <typename T, unsigned N>
class StaticQueue : public Queue
{
public:
    //! @brief Default constructor.
    StaticQueue() {}

    //! @brief Constructor.
    StaticQueue(const char * name)
    {
        Queue::init(name, m_storage, sizeof(T), N);
    }

    //! @brief Initialiser method.
    ar_status_t init(const char * name)
    {
        return Queue::init(name, m_storage, sizeof(T), N);
    }

    //! @copydoc Queue::send()
    ar_status_t send(T element, uint32_t timeout=kArInfiniteTimeout)
    {
        return Queue::send((const void *)&element, timeout);
    }

    //! @copydoc Queue::receive()
    ar_status_t receive(T * element, uint32_t timeout=kArInfiniteTimeout)
    {
        return Queue::receive((void *)element, timeout);
    }

    //! @brief Alternate form of typed receive.
    //!
    //! @param[out] resultStatus The status of the receive operation is placed here.
    //!     May be NULL, in which case no status is returned.
    //! @param timeout Maximum time in ticks to wait for a queue element.
    T receive(uint32_t timeout=kArInfiniteTimeout, ar_status_t * resultStatus=NULL)
    {
        T element;
        ar_status_t status = Queue::receive((void *)&element, timeout);
        if (resultStatus)
        {
            *resultStatus = status;
        }
        return element;
    }

protected:
    T m_storage[N]; //!< Static storage for the queue elements.

private:
    //! @brief Disable copy constructor.
    StaticQueue(const StaticQueue<T,N> & other);

    //! @brief Disable assignment operator.
    StaticQueue& operator=(const StaticQueue<T,N> & other);
};

/*!
 * @brief Timer object.
 *
 * @ingroup ar_timer
 */
class Timer : public _ar_timer
{
public:

    //! @brief Timer callback function that takes an instance of this class.
    typedef void (*callback_t)(Timer * timer, void * param);

    //! @brief Default constructor.
    Timer() {}

    //! @brief Constructor.
    Timer(const char * name, callback_t callback, void * param, ar_timer_mode_t timerMode, uint32_t delay)
    {
        init(name, callback, param, timerMode, delay);
    }

    //! @brief Destructor.
    ~Timer() { ar_timer_delete(this); }

    //! @brief Initialize the timer.
    ar_status_t init(const char * name, callback_t callback, void * param, ar_timer_mode_t timerMode, uint32_t delay);

    //! @brief Get the timer's name.
    const char * getName() const { return m_name; }

    //! @brief Start the timer running.
    void start() { ar_timer_start(this); }

    //! @brief Stop the timer.
    void stop() { ar_timer_stop(this); }

    //! @brief Returns whether the timer is currently running.
    bool isActive() const { return m_isActive; }

    //! @brief Adjust the timer's delay.
    void setDelay(uint32_t delay) { ar_timer_set_delay(this, delay); }

    //! @brief Get the current delay for the timer.
    uint32_t getDelay() const { return m_delay; }

protected:

    callback_t m_userCallback;    //!< The user timer callback.

    //! @brief Converts the timer struct to an instance of this class.
    static void timer_wrapper(ar_timer_t * timer, void * arg);

private:
    //! @brief Disable copy constructor.
    Timer(const Timer & other);

    //! @brief Disable assignment operator.
    Timer& operator=(const Timer & other);
};

/*!
 * @brief Timer object taking a member function callback.
 *
 * @ingroup ar_timer
 */
template <class T>
class TimerWithMemberCallback : public Timer
{
public:

    //! @brief Timer callback function that takes an instance of this class.
    typedef void (T::*callback_t)(Timer * timer);

    //! @brief Default constructor.
    TimerWithMemberCallback<T>() {}

    //! @brief Constructor taking a member function callback.
    TimerWithMemberCallback<T>(const char * name, T * object, callback_t callback, ar_timer_mode_t timerMode, uint32_t delay)
    {
        init(name, object, callback, timerMode, delay);
    }

    //! @brief Destructor.
    ~TimerWithMemberCallback<T>() {}

    //! @brief Initialize the timer with a member function callback.
    ar_status_t init(const char * name, T * object, callback_t callback, ar_timer_mode_t timerMode, uint32_t delay)
    {
        m_memberCallback = callback;
        return Timer::init(name, member_callback, object, timerMode, delay);
    }

protected:

    callback_t m_memberCallback;    //!< The user timer callback.

    //! @brief Call the member function.
    void invoke(T * obj)
    {
        (obj->*m_memberCallback)(this);
    }

    //! @brief Template function to invoke a callback that is a member function.
    static void member_callback(Timer * timer, void * param)
    {
        TimerWithMemberCallback<T> * _this = static_cast<TimerWithMemberCallback<T> *>(timer);
        T * obj = static_cast<T *>(param);
        _this->invoke(obj);
    }

private:
    //! @brief Disable copy constructor.
    TimerWithMemberCallback<T>(const TimerWithMemberCallback<T> & other);

    //! @brief Disable assignment operator.
    TimerWithMemberCallback<T>& operator=(const TimerWithMemberCallback<T> & other);
};

/*!
 * @brief Run loop.
 *
 * @ingroup ar_runloop
 */
class RunLoop : public _ar_runloop
{
public:
    //! @brief Default constructor.
    RunLoop() {}

    //! @brief Constructor to init the runloop.
    //! @param The runloop's name. May be NULL.
    RunLoop(const char * name)
    {
        init(name);
    }

    //! @brief Runloop destructor.
    ~RunLoop() { ar_runloop_delete(this); }

    /*!
     * @brief Create a new runloop.
     *
     * A new runloop is not associated with any thread. This association will happen when the runloop
     * is run.
     *
     * @param name The name of the runloop. May be NULL.
     *
     * @retval #kArSuccess The runloop was created successfully.
     * @retval #kArNotFromInterruptError Cannot call this API from interrupt context.
     */
    ar_status_t init(const char * name) { return ar_runloop_create(this, name); }

    //! @brief Get the run loop's name.
    const char * getName() const { return m_name; }

    /*!
     * @brief Run a runloop for a period of time.
     *
     * Starts the runloop running for a specified amount of time. It will sleep the thread until an
     * associated timer or source is pending. If the timeout expires, the API will return. To force the
     * runloop to exit, call ar_runloop_stop().
     *
     * It's ok to nest runs of the runloop, but only on a single thread.
     *
     * If a queue is associated with the runloop (via ar_runloop_add_queue()) and the queue receives
     * an item, then the runloop will either invoke the queue handler callback or exit. If it exits,
     * it will return #kArRunLoopQueueReceived and the @a object parameter will be filled in with the
     * queue object that received the item. If @a object is NULL, then the runloop will still exit but
     * you cannot tell which queue received. This is acceptable if only one queue is associated with
     * the runloop.
     *
     * @param timeout The maximum number of milliseconds to run the runloop. If this value is 0, or
     *      #kArNoTimeout, then the call will exit after handling pending sources. Setting the timeout to
     *      #kArInfiniteTimeout will cause the runloop to run until stopped or a queue receives an item.
     * @param[out] object Optional structure that will be filled in when the return value is #kArRunLoopQueueReceived.
     *      May be NULL, in which case the receiving queue cannot be indicated.
     *
     * @retval #kArRunLoopStopped The runloop exited due to a timeout or explict call to ar_runloop_stop().
     * @retval #kArRunLoopQueueReceived A queue associated with the runloop received an item.
     * @retval #kArTimeoutError The runloop timed out.
     * @retval #kArRunLoopAlreadyRunningError The runloop is already running on another thread, or another
     *      runloop is already running on the current thread.
     * @retval #kArNotFromInterruptError Cannot run a runloop from interrupt context.
     */
    ar_status_t run(uint32_t timeout=kArInfiniteTimeout, ar_runloop_result_t * object=0) { return ar_runloop_run(this, timeout, object); }

    /*!
     * @brief Stop a runloop.
     *
     * Use this function to stop a running runloop. It may be called from any execution context, including
     * from within the runloop itself, another thread, or interrupt context. When the runloop stops, it
     * will return #kArRunLoopStopped from the run() API. If multiple runs of the runloop
     * are nested, only the innermost will be stopped. If the runloop is calling out to a perform function
     * or a handler callback, it will only be stopped when the callback returns.
     *
     * @retval #kArSuccess The runloop was stopped, or was already stopped.
     */
    ar_status_t stop() { return ar_runloop_stop(this); }

    /*!
     * @brief Invoke a function on a runloop.
     *
     * The function will be called in FIFO order the next time the runloop runs. If the runloop is
     * asleep, it will be woken and run immediately.
     *
     * This API can be called from any execution context.
     *
     * @param function The function to invoke on the runloop.
     * @param param Arbitrary parameter passed to the function when it is called.
     *
     * @retval #kArSuccess The runloop was stopped, or was already stopped.
     * @retval #kArInvalidParameterError The _function_ parameter was NULL.
     * @retval #kArQueueFullError No room to enqueue the function.
     */
    ar_status_t perform(ar_runloop_function_t function, void * param=0) { return ar_runloop_perform(this, function, param); }

    /*!
     * @brief Associate a timer with a runloop.
     *
     * If the timer is already associated with another runloop, its association will be changed.
     *
     * @param timer The timer to associate with the runloop.
     *
     * @retval #kArSuccess The timer was added to the runloop.
     * @retval #kArInvalidParameterError The _timer_ parameter was NULL.
     */
    ar_status_t addTimer(ar_timer_t * timer) { return ar_runloop_add_timer(this, timer); }

    /*!
     * @brief Add a queue to a runloop.
     *
     * If the queue is already associated with another runloop, the #kArAlreadyAttachedError error
     * is returned.
     *
     * @param queue The queue to associate with the runloop.
     * @param callback Optional callback to handler an item received on the queue. May be NULL.
     * @param param Arbitrary parameter passed to the _callback_ when it is called.
     *
     * @retval #kArSuccess The timer was added to the runloop.
     * @retval #kArAlreadyAttachedError A queue can only be added to one runloop at a time.
     * @retval #kArInvalidParameterError The _queue_ parameter was NULL.
     */
    ar_status_t addQueue(ar_queue_t * queue, ar_runloop_queue_handler_t callback=NULL, void * param=NULL) { return ar_runloop_add_queue(this, queue, callback, param); }

    /*!
     * @brief Return the current runloop.
     *
     * @return The runloop currently running on the active thread. If no runloop is running, then NULL
     *      will be returned.
     */
    static ar_runloop_t * getCurrent(void) { return ar_runloop_get_current(); }
};

} // namespace Ar

#endif // defined(__cplusplus)

#endif // _AR_CLASSES_H_
//------------------------------------------------------------------------------
// EOF
//------------------------------------------------------------------------------


text:
npm-scope(7) -- Scoped packages
===============================

## DESCRIPTION

All npm packages have a name. Some package names also have a scope. A scope
follows the usual rules for package names (url-safe characters, no leading dots
or underscores). When used in package names, preceded by an @-symbol and
followed by a slash, e.g.

    @somescope/somepackagename

Scopes are a way of grouping related packages together, and also affect a few
things about the way npm treats the package.

Scoped packages can be published and installed as of `npm@2` and are supported
by the primary npm registry. The npm client is backwards-compatible with
un-scoped registries, so it can be used to work with scoped and un-scoped
registries at the same time.

## Installing scoped packages

Scoped packages are installed to a sub-folder of the regular installation
folder, e.g. if your other packages are installed in `node_modules/packagename`,
scoped modules will be in `node_modules/@myorg/packagename`. The scope folder
(`@myorg`) is simply the name of the scope preceded by an @-symbol, and can
contain any number of scoped packages.

A scoped package is installed by referencing it by name, preceded by an
@-symbol, in `npm install`:

    npm install @myorg/mypackage

Or in `package.json`:

    "dependencies": {
      "@myorg/mypackage": "^1.3.0"
    }

Note that if the @-symbol is omitted in either case npm will instead attempt to
install from GitHub; see `npm-install(1)`.

## Requiring scoped packages

Because scoped packages are installed into a scope folder, you have to
include the name of the scope when requiring them in your code, e.g.

    require('@myorg/mypackage')

There is nothing special about the way Node treats scope folders, this is
just specifying to require the module `mypackage` in the folder called `@myorg`.

## Publishing scoped packages

Scoped packages can be published from the CLI as of `npm@2` and can be
published to any registry that supports them, including the primary npm
registry.

(As of 2015-04-19, and with npm 2.0 or newer, the primary npm registry **does**
support scoped packages)

If you wish, you may associate a scope with a registry; see below.

### Publishing public scoped packages to the primary npm registry

To publish a public scoped package, you must specify `--access public` with
the initial publication.  This will publish the package and set access
to `public` as if you had run `npm access public` after publishing.

### Publishing private scoped packages to the npm registry

To publish a private scoped package to the npm registry, you must have
an [npm Private Modules](https://www.npmjs.com/private-modules)
account.

You can then publish the module with `npm publish` or `npm publish
--access restricted`, and it will be present in the npm registry, with
restricted access.  You can then change the access permissions, if
desired, with `npm access` or on the npmjs.com website.

## Associating a scope with a registry

Scopes can be associated with a separate registry. This allows you to
seamlessly use a mix of packages from the primary npm registry and one or more
private registries, such as npm Enterprise.

You can associate a scope with a registry at login, e.g.

    npm login --registry=http://reg.example.com --scope=@myco

Scopes have a many-to-one relationship with registries: one registry can
host multiple scopes, but a scope only ever points to one registry.

You can also associate a scope with a registry using `npm config`:

    npm config set @myco:registry http://reg.example.com

Once a scope is associated with a registry, any `npm install` for a package
with that scope will request packages from that registry instead. Any
`npm publish` for a package name that contains the scope will be published to
that registry instead.

## SEE ALSO

* npm-install(1)
* npm-publish(1)
* npm-access(1)

redpajama_set_name: RedPajamaGithub


text:
\documentclass{article}
\usepackage{listings}
\usepackage{upquote}
\usepackage{verbatim}

\lstnewenvironment{likely}{
  \lstset{
    basicstyle=\ttfamily,
    showstringspaces=false
  }}{}

\title{Face Recognition in Likely}
\author{Joshua C. Klontz}
\date{\today}
\begin{document}
\maketitle

\begin{abstract}
This document represents a long-term effort to port the OpenBR face recognition algorithm to \emph{Likely}\footnote{www.liblikely.org}.
As Likely is a literate programming language, this document is both the source code \emph{and} the documentation.
\end{abstract}

\section{Compilation}
\label{sec:compilation}
This document is a valid \LaTeX\ file that can be rendered for reading by humans.

\begin{verbatim}
$ pdflatex face_recognition.tex
\end{verbatim}

It is also a valid Likely file that can be trained/compiled for reading by machines.

\begin{verbatim}
$ likely -p 'data := "path/to/training/data.lm".read-matrix' \
face_recognition.tex face_recognition.o
\end{verbatim}

Note that the outputted \texttt{face\_recognition.o} native object file exposes its functionality through a C-compatible signature.

\begin{verbatim}
#include <likely.h>
likely_mat face_recognition(likely_const_mat src);
\end{verbatim}

\section{Introduction}
We start our journey constructing the face recognition algorithm with an identity function.

\begin{likely}
face-recognition :=
  src :->
    src
\end{likely}

Throughout the remainder of this document we will append additional steps to this function, building up the entire algorithm one transformation at a time.
It is the responsibility of each section in this document to update the \texttt{face-recognition} function and the training \texttt{data}.
It is in this way that the sections maintain independence, and the algorithm can be changed by inserting, removing, or editing sections of this document.
Remember that the \emph{Likely Language Reference}\footnote{https://s3.amazonaws.com/liblikely/latex/standard.pdf} is a good resource to consult if you are uncertain about the meaning of some code.

Note that the remainder of this document assumes that the global variable
\texttt{data} is defined, and contains the appropriate training samples.

\begin{likely}
"Number of training samples:"
data.frames
\end{likely}

\section{...}
This section serves as a placeholder for the unwritten algorithm steps.
There are a lot of steps that haven't been written yet, including face detection, registration and representation!
In fact, only the final few sections of the algorithm have been written.

\section{L2 Normalization}
We wish to normalize every feature vector to a unit L2 norm, ensuring that they live on a high-dimensional unit sphere.
Such a normalization has been observed to improve accuracy when comparing feature vectors using a Euclidean distance.

\begin{likely}
normalize-l2 :=
  src :->
  {
    dst := src.imitate
    len := src.columns
    ((src.channels 1 src.rows src.frames)
     dst src len) :=>
    {
      norm := 0.(cast src).$
      (iter (-> x (<- norm (+ norm src.sq)))
            len)
      norm := (/ 1 (sqrt norm))
      (iter (-> x (<- dst (* src norm)))
            len)
    }
  }
\end{likely}

Now we can re-define \texttt{face-recognition} to append L2 normalization.

\begin{likely}
face-recognition :=
  src :->
    src.face-recognition.normalize-l2
\end{likely}

And project the training data.

\begin{likely}
data := [ data.normalize-l2 ]
\end{likely}

\section{Quantization}
The goal of quantization is to rescale and cast feature vector dimensions into 8-bit unsigned integers.
The resulting feature vectors are smaller in size and faster to compare, with generally negligible loss in representation accuracy.
Training data is required to determine the scaling parameters.

\begin{likely}
train-quantize :=
  (training-samples) :->
  {
    lo    := [ training-samples.min-element  ]
    hi    := [ training-samples.max-element  ]
    scale := [ (/ 255 (- hi lo)) ]

    src :->
    {
      dst := (imitate-size src (imitate-dimensions u8 src.type))
      (dst src) :=>
        dst :<- src.(- lo).(* scale)
    }
  }

quantize := (train-quantize data)
\end{likely}

Now we can re-define \texttt{face-recognition} to append quantization.

\begin{likely}
face-recognition :=
  src :->
    src.face-recognition.quantize
\end{likely}

And project the training data.

\begin{likely}
data := [ data.quantize ]
\end{likely}

And report some statistics.

\begin{likely}
"Quantized feature vector dimensionality:"
data.columns
\end{likely}

\section{Entry Point}
Recall from section \ref{sec:compilation} that the entry point to the outside world is a single C function \texttt{face\_recognition} that takes as input a \texttt{likely\_mat} (the input image) and outputs a new \texttt{likely\_mat} (the feature vector). Now that we have finished defining \texttt{face-recognition} we can finally export this symbol.

\begin{likely}
(extern u8X "face_recognition" f32X face-recognition)
\end{likely}

\end{document}


text:
package com.gemstone.gemfire.cache.hdfs.internal;

import java.io.File;
import java.io.IOException;
import java.util.ArrayList;

import org.apache.commons.io.FileUtils;
import org.apache.hadoop.fs.FileStatus;
import org.apache.hadoop.fs.Path;
import org.apache.hadoop.hdfs.MiniDFSCluster;

import com.gemstone.gemfire.cache.Region;
import com.gemstone.gemfire.cache.hdfs.HDFSEventQueueAttributes;
import com.gemstone.gemfire.cache.hdfs.HDFSEventQueueAttributesFactory;
import com.gemstone.gemfire.cache.hdfs.HDFSStore;
import com.gemstone.gemfire.cache.hdfs.HDFSStoreMutator;
import com.gemstone.gemfire.cache.hdfs.HDFSStore.HDFSCompactionConfig;
import com.gemstone.gemfire.cache.hdfs.HDFSStoreMutator.HDFSCompactionConfigMutator;
import com.gemstone.gemfire.cache.hdfs.HDFSStoreMutator.HDFSEventQueueAttributesMutator;
import com.gemstone.gemfire.cache.hdfs.internal.hoplog.BaseHoplogTestCase;
import com.gemstone.gemfire.cache.hdfs.internal.hoplog.HDFSRegionDirector.HdfsRegionManager;
import com.gemstone.gemfire.cache.hdfs.internal.hoplog.HFileSortedOplog;
import com.gemstone.gemfire.cache.hdfs.internal.hoplog.HdfsSortedOplogOrganizer;
import com.gemstone.gemfire.cache.hdfs.internal.hoplog.Hoplog;
import com.gemstone.gemfire.internal.AvailablePortHelper;
import com.gemstone.gemfire.internal.cache.LocalRegion;
import com.gemstone.gemfire.internal.util.BlobHelper;

public class HdfsStoreImplJUnitTest extends BaseHoplogTestCase {
  public void testAlterAttribute() throws Exception {
    assertEquals(HDFSStore.DEFAULT_MAX_WRITE_ONLY_FILE_SIZE, hdfsStore.getMaxFileSize());
    assertEquals(HDFSStore.DEFAULT_WRITE_ONLY_FILE_ROLLOVER_INTERVAL, hdfsStore.getFileRolloverInterval());

    HDFSCompactionConfig compConfig = hdfsStore.getHDFSCompactionConfig();
    assertEquals(HDFSCompactionConfig.DEFAULT_MAX_INPUT_FILE_COUNT, compConfig.getMaxInputFileCount());
    assertEquals(HDFSCompactionConfig.DEFAULT_MAX_INPUT_FILE_SIZE_MB, compConfig.getMaxInputFileSizeMB());
    assertEquals(HDFSCompactionConfig.DEFAULT_MAX_THREADS, compConfig.getMaxThreads());
    assertEquals(HDFSCompactionConfig.DEFAULT_MIN_INPUT_FILE_COUNT, compConfig.getMinInputFileCount());
    assertFalse(compConfig.getAutoCompaction());

    assertEquals(HDFSCompactionConfig.DEFAULT_MAJOR_COMPACTION_INTERVAL_MINS, compConfig.getMajorCompactionIntervalMins());
    assertEquals(HDFSCompactionConfig.DEFAULT_MAJOR_COMPACTION_MAX_THREADS, compConfig.getMajorCompactionMaxThreads());
    assertFalse(compConfig.getAutoMajorCompaction());

    assertEquals(HDFSCompactionConfig.DEFAULT_OLD_FILE_CLEANUP_INTERVAL_MINS, compConfig.getOldFilesCleanupIntervalMins());

    HDFSEventQueueAttributes qAttr = hdfsStore.getHDFSEventQueueAttributes();
    assertEquals(HDFSEventQueueAttributesFactory.DEFAULT_BATCH_SIZE_MB, qAttr.getBatchSizeMB());
    assertEquals(HDFSEventQueueAttributesFactory.DEFAULT_BATCH_TIME_INTERVAL_MILLIS, qAttr.getBatchTimeInterval());

    HDFSStoreMutator mutator = hdfsStore.createHdfsStoreMutator();
    HDFSCompactionConfigMutator compMutator = mutator.getCompactionConfigMutator();
    HDFSEventQueueAttributesMutator qMutator = mutator.getHDFSEventQueueAttributesMutator();

    mutator.setMaxFileSize(234);
    mutator.setFileRolloverInterval(121);

    compMutator.setMaxInputFileCount(87);
    compMutator.setMaxInputFileSizeMB(45);
    compMutator.setMinInputFileCount(34);
    compMutator.setMaxThreads(843);
    compMutator.setAutoCompaction(true);

    compMutator.setMajorCompactionIntervalMins(26);
    compMutator.setMajorCompactionMaxThreads(92);
    compMutator.setAutoMajorCompaction(true);

    compMutator.setOldFilesCleanupIntervalMins(328);

    qMutator.setBatchSizeMB(985);
    qMutator.setBatchTimeInterval(695);

    hdfsStore.alter(mutator);

    assertEquals(234, hdfsStore.getMaxFileSize());
    assertEquals(121, hdfsStore.getFileRolloverInterval());

    compConfig = hdfsStore.getHDFSCompactionConfig();
    assertEquals(87, compConfig.getMaxInputFileCount());
    assertEquals(45, compConfig.getMaxInputFileSizeMB());
    assertEquals(843, compConfig.getMaxThreads());
    assertEquals(34, compConfig.getMinInputFileCount());
    assertTrue(compConfig.getAutoCompaction());

    assertEquals(26, compConfig.getMajorCompactionIntervalMins());
    assertEquals(92, compConfig.getMajorCompactionMaxThreads());
    assertTrue(compConfig.getAutoMajorCompaction());

    assertEquals(328, compConfig.getOldFilesCleanupIntervalMins());

    qAttr = hdfsStore.getHDFSEventQueueAttributes();
    assertEquals(985, qAttr.getBatchSizeMB());
    assertEquals(695, qAttr.getBatchTimeInterval());
  }

  public void testSameHdfsMultiStore() throws Exception {
    int port = AvailablePortHelper.getRandomAvailableTCPPort();
    MiniDFSCluster cluster = initMiniCluster(port ,1);
    // create store with config file
    hsf.setHomeDir("Store-1");
    File confFile = new File("HdfsStoreImplJUnitTest-Store-1");
    String conf = "<configuration>\n             "
        + "  <property>\n                                    "
        + "    <name>dfs.block.size</name>\n                 "
        + "    <value>1024</value>\n                         "
        + "  </property>\n                                   "
        + "  <property>\n                                    "
        + "    <name>fs.default.name</name>\n                "
        + "    <value>hdfs://127.0.0.1:" + port + "</value>\n"
        + "  </property>\n                                   "
        + "</configuration>";
    setConfigFile(hsf, confFile, conf);
    HDFSStoreImpl store1 = (HDFSStoreImpl) hsf.create("Store-1");
    confFile.delete();

    // create region with store
    regionfactory.setHDFSStoreName(store1.getName());
    Region<Object, Object> region1 = regionfactory.create("region-1");

    // populate data and check block size
    Path path = new Path("Store-1/region-1/0/1-1-1.hop");
    Hoplog oplog = new HFileSortedOplog(store1, path,
        store1.getBlockCache(), director.getHdfsRegionStats("/region-1"),
        store1.getStats());
    createHoplog(10, oplog);

    FileStatus[] status = store1.getFileSystem().listStatus(path);
    assertEquals(1024, status[0].getBlockSize());

    // create store with config file
    hsf.setHomeDir("Store-2");
    confFile = new File("HdfsStoreImplJUnitTest-Store-2");
    conf = "<configuration>\n             "
        + "  <property>\n                                    "
        + "    <name>dfs.block.size</name>\n                 "
        + "    <value>2048</value>\n                         "
        + "  </property>\n                                   "
        + "  <property>\n                                    "
        + "    <name>fs.default.name</name>\n                "
        + "    <value>hdfs://127.0.0.1:" + port + "</value>\n"
        + "  </property>\n                                   "
        + "</configuration>";
    setConfigFile(hsf, confFile, conf);
    HDFSStoreImpl store2 = (HDFSStoreImpl) hsf.create("Store-2");
    confFile.delete();

    // create region with store
    regionfactory.setHDFSStoreName(store2.getName());
    Region<Object, Object> region2 = regionfactory.create("region-2");

    // populate data and check block size
    path = new Path("Store-2/region-2/0/1-1-1.hop");
    oplog = new HFileSortedOplog(store2, path,
        store2.getBlockCache(), director.getHdfsRegionStats("/region-2"),
        store2.getStats());
    createHoplog(10, oplog);

    status = store2.getFileSystem().listStatus(path);
    assertEquals(2048, status[0].getBlockSize());

    // cleanup
    region1.destroyRegion();
    store1.destroy();
    region2.destroyRegion();
    store2.destroy();
    cleanupCluster(cluster);
  }

  public void testSameHdfsMultiStoreOneClose() throws Exception {
    int port = AvailablePortHelper.getRandomAvailableTCPPort();
    MiniDFSCluster cluster = initMiniCluster(port ,1);
    byte[] keyBytes5 = BlobHelper.serializeToBlob("5");

    hsf.setHomeDir("Store-1");
    hsf.setNameNodeURL("hdfs://127.0.0.1:" + port);
    HDFSStoreImpl store1 = (HDFSStoreImpl) hsf.create("Store-1");
    // create region with store
    regionfactory.setHDFSStoreName(store1.getName());
    Region<Object, Object> region1 = regionfactory.create("region-1");
    HdfsRegionManager regionManager1 = ((LocalRegion)region1).getHdfsRegionManager();
    HdfsSortedOplogOrganizer organizer1 = new HdfsSortedOplogOrganizer(regionManager1, 0);
    // flush and create hoplog
    ArrayList<TestEvent> items = new ArrayList<TestEvent>();
    for (int i = 0; i < 100; i++) {
      items.add(new TestEvent("" + i, "" + i));
    }
    organizer1.flush(items.iterator(), items.size());
    assertEquals("5", organizer1.read(keyBytes5).getValue());

    hsf.setHomeDir("Store-2");
    hsf.setNameNodeURL("hdfs://127.0.0.1:" + port);
    HDFSStoreImpl store2 = (HDFSStoreImpl) hsf.create("Store-2");
    // create region with store
    regionfactory.setHDFSStoreName(store2.getName());
    Region<Object, Object> region2 = regionfactory.create("region-2");
    HdfsRegionManager regionManager2 = ((LocalRegion)region2).getHdfsRegionManager();
    HdfsSortedOplogOrganizer organizer2 = new HdfsSortedOplogOrganizer(regionManager2, 0);
    organizer2.flush(items.iterator(), items.size());

    // close region one and then check if region 2 is still readable
    region1.destroyRegion();
    store1.destroy();
    assertEquals("5", organizer2.read(keyBytes5).getValue());

    region2.destroyRegion();
    store2.destroy();
    cleanupCluster(cluster);
  }

  public void testCheckAndFixFs() throws Exception {
    deleteMiniClusterDir();

    int port = AvailablePortHelper.getRandomAvailableTCPPort();
    MiniDFSCluster cluster = initMiniCluster(port ,1);
    // create store with config file
    hsf.setHomeDir("Store-1");
    File confFile = new File(getName() + ".xml");
    String conf = "<configuration>\n             "
        + "  <property>\n                                    "
        + "    <name>dfs.block.size</name>\n                 "
        + "    <value>1024</value>\n                         "
        + "  </property>\n                                   "
        + "  <property>\n                                    "
        + "    <name>fs.default.name</name>\n                "
        + "    <value>hdfs://127.0.0.1:" + port + "</value>\n"
        + "  </property>\n                                   "
        + "</configuration>";
    setConfigFile(hsf, confFile, conf);
    HDFSStoreImpl store1 = (HDFSStoreImpl) hsf.create("Store-1");

    assertTrue(store1.getFileSystem().exists(new Path("/")));
    assertTrue(store1.getCachedFileSystem().exists(new Path("/")));

    store1.getFileSystem().close();
    cache.getLogger().info("<ExpectedException action=add>java.io.IOException</ExpectedException>");
    try {
      store1.getCachedFileSystem().exists(new Path("/"));
      fail();
    } catch (IOException e) {
      // expected
    }

    store1.checkAndClearFileSystem();
    cache.getLogger().info("<ExpectedException action=remove>java.io.IOException</ExpectedException>");

    assertTrue(store1.getFileSystem().exists(new Path("/")));
    assertTrue(store1.getCachedFileSystem().exists(new Path("/")));
    confFile.delete();
    cleanupCluster(cluster);
  }

  void cleanupCluster(MiniDFSCluster cluster) throws Exception {
    cluster.shutdown();
    FileUtils.deleteDirectory(new File("hdfs-test-cluster"));
  }
}


text:
'use strict';

var expect = require('chai').expect;
var angular = require('angular');

var helloWorldModule = require('./helloWorld.controller');
var calculatorModule = require('../services/calculator/calculator.service');

describe('helloWorld', function() {
	var $controller;
	var mockCalculator;

	beforeEach(function() {
		angular.mock.module(helloWorldModule.moduleName);

		mockCalculator = {
			calculateResult: null,
			calculate: sinon.spy(function() { return mockCalculator.calculateResult; }),
		};

		angular.mock.module(function ($provide) {
			$provide.value(calculatorModule.factoryName, mockCalculator);
		});

		angular.mock.inject(['$controller', function(_$controller_) {
			$controller = _$controller_;
		}]);
	});

	it('should have a message', function() {
		var controller = buildController();
		expect(controller.message).to.equal('Hello Angular explorers!')
	});

	it('should calculate the result of the operands and operator', function() {
		var controller = buildController();

		controller.operand1 = 5;
		controller.operand2 = 10;
		controller.operator = '*';
		mockCalculator.calculateResult = 'mocked result';

		controller.equals();

		expect(controller.result).to.equal('mocked result');
		expect(controller.error).to.be.null;

		sinon.assert.calledOnce(mockCalculator.calculate);
		sinon.assert.calledWith(mockCalculator.calculate, '*', 5, 10);
	});

	function buildController() {
		return $controller(helloWorldModule.controllerName);
	}
});


text:
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
<title>shared_library
      class</title>
<link rel="stylesheet" href="../../boostbook.css" type="text/css">
<meta name="generator" content="DocBook XSL Stylesheets V1.67.2">
<link rel="start" href="../../index.html" title="Chapter 1. Boost.Extension">
<link rel="up" href="../shared_libraries.html" title=" Shared Libraries">
<link rel="prev" href="shared_library_inefficiencies.html" title="
      Possible Inefficiencies in Shared Libraries">
<link rel="next" href="../tutorials.html" title="Tutorials">

Home
Libraries
People
FAQ
More

shared_library
      class

        Provides for automatic loading of named modules, and retrieval of functions
        in those modules:

shared_library m("my_module_name");
// Call a function that returns an int and takes a float parameter.
int result = m.get<int, float>("function_name")(5.0f);
m.close();

        The get()
        function returns a function pointer that can be wrapped in Boost.Function
        objects or used by itself.

        Reference: shared_library

Copyright © 2008 Jeremy Pack

        Distributed under the Boost Software License, Version 1.0. (See accompanying
        file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)


text:
IPAddress::IPAddress()
{
    memset(_address.a8, 0, sizeof(_address));
}

IPAddress::IPAddress(uint8_t first_octet, uint8_t second_octet, uint8_t third_octet, uint8_t fourth_octet)
{
    _address.a8[0] = first_octet;
    _address.a8[1] = second_octet;
    _address.a8[2] = third_octet;
    _address.a8[3] = fourth_octet;
}

IPAddress::IPAddress(uint32_t address)
{
	_address.a32=address;
}

IPAddress::IPAddress(const uint8_t *address)
{
    memcpy(_address.a8, address, sizeof(_address));
}

IPAddress& IPAddress::operator=(const uint8_t *address)
{
    memcpy(_address.a8, address, sizeof(_address));
    return *this;
}

IPAddress& IPAddress::operator=(uint32_t address)
{
	_address.a32=address;
    return *this;
}

bool IPAddress::operator==(const uint8_t* addr)
{
    return memcmp(addr, _address.a8, sizeof(_address)) == 0;
}

size_t IPAddress::printTo(Print& p) const
{
    size_t n = 0;
    for (int i =0; i < 3; i++)
    {
        n += p.print(_address.a8[i], DEC);
        n += p.print('.');
    }
    n += p.print(_address.a8[3], DEC);
    return n;
}


text:
package com.ansteel.common.tpl.core;

import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;

import javax.servlet.http.HttpServletRequest;

import com.ansteel.core.constant.Public;
import com.ansteel.core.exception.PageException;
import com.ansteel.core.query.Operator;
import com.ansteel.core.utils.StringUtils;
import com.ansteel.dhtmlx.widget.form.FormFactory;
import com.ansteel.dhtmlx.widget.form.Options;
import com.ansteel.dhtmlx.widget.formoption.IFormOption;
import com.ansteel.dhtmlx.widget.formoption.OperatorOption;
import com.ansteel.common.prentmodel.domain.FieldsForm;
import com.ansteel.common.prentmodel.domain.FieldsQuery;

/**
 * 创 建 人:gugu
 * 创建日期:2015-05-19
 * 修 改 人:
 * 修改日 期:
 * 描   述:Dhtmlx查询。
 */
public class DhtmlxQuery {
	/**
	 * 得到查询信息
	 * @param cuntentFieldsCategory 当前模型分类
	 * @param nameMap 模型名称映射
	 * @param typeMap 字段类型,用于判断默认操作符
	 * @return
	 */
	public QueryInfo getQueryInfo(List<FieldsQuery> fieldsQuery,List<FieldsForm> fieldsForm,
			Map<String, String> nameMap,Map<String, String> typeMap,HttpServletRequest request) {
		QueryInfo queryInfo = this.getQueryInfo(fieldsQuery,nameMap,typeMap,request);
		this.setValueMapAndFormType(queryInfo,fieldsForm,request);
		return queryInfo;
	}

	private QueryInfo getQueryInfo(List<FieldsQuery> fieldsQuery,
			Map<String, String> nameMap,Map<String, String> typeMap,HttpServletRequest request) {
		QueryInfo queryInfo = new QueryInfo();
		List<Options>  options = new ArrayList<Options>();
		Map<String, List<Options>> operatorMap=new LinkedHashMap<String, List<Options>>();
		Map<String, Boolean> oftenMap=new LinkedHashMap<String, Boolean>();
		for(FieldsQuery f:fieldsQuery){
			if(1==f.getIsShow()){
				options.add(this.getNameOption(f,nameMap));
				String name = f.getName();
				operatorMap.put(name, this.getOperatorMap(f,typeMap));
				if(f.getIsOften()!=null&&1==f.getIsOften()){
					oftenMap.put(name, true);
				}else{
					oftenMap.put(name, false);
				}
			}
		}
		queryInfo.setNameList(options);
		queryInfo.setOperatorMap(operatorMap);
		queryInfo.setOftenMap(oftenMap);
		return queryInfo;
	}

	private void setValueMapAndFormType(QueryInfo queryInfo,List<FieldsForm> fieldsForm,HttpServletRequest request) {
		Map<String, List<Options>> optionMap=new LinkedHashMap<String, List<Options>>();
		Map<String, String> formTypeMap=new LinkedHashMap<String, String>();
		FormFactory formFactory = new FormFactory();
		for(FieldsForm f:fieldsForm){
			List<Options>  options = formFactory.getOptions(f,request);
			if(options!=null&&options.size()>0){
				//加入空选项
				List<Options>  optionEmpty = new ArrayList<Options>();
				Options option = new Options();
				option.setText("");
				option.setValue("");
				optionEmpty.add(option);
				optionEmpty.addAll(options);
				optionMap.put(f.getName(), optionEmpty);
			}
			formTypeMap.put(f.getName(), f.getType());
		}
		queryInfo.setValueMap(optionMap);
		queryInfo.setFormTypeMap(formTypeMap);
	}

	private Map<String, List<Options>> getValueMap(List<FieldsForm> fieldsForm,HttpServletRequest request) {
		Map<String, List<Options>> optionMap=new LinkedHashMap<String, List<Options>>();
		FormFactory formFactory = new FormFactory();
		for(FieldsForm f:fieldsForm){
			List<Options>  options = formFactory.getOptions(f,request);
			if(options!=null&&options.size()>0){
				//加入空选项
				List<Options>  optionEmpty = new ArrayList<Options>();
				Options option = new Options();
				option.setText("");
				option.setValue("");
				optionEmpty.add(option);
				optionEmpty.addAll(options);
				optionMap.put(f.getName(), optionEmpty);
			}
		}
		return optionMap;
	}

	private List<Options> getOperatorMap(FieldsQuery f,Map<String, String> typeMap) {
		IFormOption formOption = new OperatorOption();
		List<Options> options = formOption.get(f.getOperatorCode());
		if(options.size()>0){
			return options;
		}else{
			String name = f.getName();
			if(typeMap.containsKey(name)){
				if(!StringUtils.hasText(typeMap.get(name))){
					throw new PageException("请设置【"+name+"】字段数据类型!");
				}
				if(typeMap.get(name).equalsIgnoreCase(Public.STRING)){
					Options likeOption = new Options();
					likeOption.setText(Operator.LIKE.getAlias());
					likeOption.setValue(Operator.LIKE.getCode());
					options.add(likeOption);
				}
			}
			Options option = new Options();
			option.setText(Operator.EQ.getAlias());
			option.setValue(Operator.EQ.getCode());
			options.add(option);
			return options;
		}
	}

	private Options getNameOption(FieldsQuery f,Map<String, String> nameMap) {
		String name = f.getName();
		Options option = new Options();
		option.setText(nameMap.get(name));
		option.setValue(f.getName());
		return option;
	}

}