text:
/* Memory Layout of a SafeArray:
 *
 * -0x10: start of memory.
 * -0x10: GUID for VT_DISPATCH and VT_UNKNOWN safearrays (if FADF_HAVEIID)
 * -0x04: DWORD varianttype; (for all others, except VT_RECORD) (if FADF_HAVEVARTYPE)
 *  -0x4: IRecordInfo* iface;  (if FADF_RECORD, for VT_RECORD (can be NULL))
 *  0x00: SAFEARRAY,
 *  0x10: SAFEARRAYBOUNDS[0...]
 */

#include "config.h"

#include <string.h>
#include <stdarg.h>
#include <stdio.h>

#define COBJMACROS

#include "windef.h"
#include "winerror.h"
#include "winbase.h"
#include "variant.h"
#include "wine/debug.h"

WINE_DEFAULT_DEBUG_CHANNEL(variant);

/************************************************************************
 * SafeArray {OLEAUT32}
 *
 * NOTES
 * The SafeArray data type provides the underlying interface for Ole
 * Automations arrays, used for example to represent array types in
 * Visual Basic(tm) and to gather user defined parameters for invocation through
 * an IDispatch interface.
 *
 * Safe arrays provide bounds checking and automatically manage the data
 * types they contain, for example handing reference counting and copying
 * of interface pointers. User defined types can be stored in arrays
 * using the IRecordInfo interface.
 *
 * There are two types of SafeArray, normal and vectors. Normal arrays can have
 * multiple dimensions and the data for the array is allocated separately from
 * the array header. This is the most flexible type of array. Vectors, on the
 * other hand, are fixed in size and consist of a single allocated block, and a
 * single dimension.
 *
 * DATATYPES
 * The following types of data can be stored within a SafeArray.
 * Numeric:
 *|  VT_I1, VT_UI1, VT_I2, VT_UI2, VT_I4, VT_UI4, VT_I8, VT_UI8, VT_INT, VT_UINT,
 *|  VT_R4, VT_R8, VT_CY, VT_DECIMAL
 * Interfaces:
 *|  VT_DISPATCH, VT_UNKNOWN, VT_RECORD
 * Other:
 *|  VT_VARIANT, VT_INT_PTR, VT_UINT_PTR, VT_BOOL, VT_ERROR, VT_DATE, VT_BSTR
 *
 * FUNCTIONS
 *  BstrFromVector()
 *  VectorFromBstr()
 */

/* Undocumented hidden space before the start of a SafeArray descriptor */
#define SAFEARRAY_HIDDEN_SIZE sizeof(GUID)

/* Allocate memory */
static inline LPVOID SAFEARRAY_Malloc(ULONG ulSize)
{
  /* FIXME: Memory should be allocated and freed using a per-thread IMalloc
   *        instance returned from CoGetMalloc().
   */
  return HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, ulSize);
}

/* Free memory */
static inline BOOL SAFEARRAY_Free(LPVOID lpData)
{
  return HeapFree(GetProcessHeap(), 0, lpData);
}

/* Get the size of a supported VT type (0 means unsupported) */
static DWORD SAFEARRAY_GetVTSize(VARTYPE vt)
{
  switch (vt)
  {
    case VT_I1:
    case VT_UI1:      return sizeof(BYTE);
    case VT_BOOL:
    case VT_I2:
    case VT_UI2:      return sizeof(SHORT);
    case VT_I4:
    case VT_UI4:
    case VT_R4:
    case VT_ERROR:    return sizeof(LONG);
    case VT_R8:
    case VT_I8:
    case VT_UI8:      return sizeof(LONG64);
    case VT_INT:
    case VT_UINT:     return sizeof(INT);
    case VT_INT_PTR:
    case VT_UINT_PTR: return sizeof(UINT_PTR);
    case VT_CY:       return sizeof(CY);
    case VT_DATE:     return sizeof(DATE);
    case VT_BSTR:     return sizeof(BSTR);
    case VT_DISPATCH: return sizeof(LPDISPATCH);
    case VT_VARIANT:  return sizeof(VARIANT);
    case VT_UNKNOWN:  return sizeof(LPUNKNOWN);
    case VT_DECIMAL:  return sizeof(DECIMAL);
    /* Note: Return a non-zero size to indicate vt is valid. The actual size
     * of a UDT is taken from the result of IRecordInfo_GetSize().
     */
    case VT_RECORD:   return 32;
  }
  return 0;
}

/* Set the hidden data for an array */
static inline void SAFEARRAY_SetHiddenDWORD(SAFEARRAY* psa, DWORD dw)
{
  /* Implementation data is stored in the 4 bytes before the header */
  LPDWORD lpDw = (LPDWORD)psa;
  lpDw[-1] = dw;
}

/* Get the hidden data from an array */
static inline DWORD SAFEARRAY_GetHiddenDWORD(SAFEARRAY* psa)
{
  LPDWORD lpDw = (LPDWORD)psa;
  return lpDw[-1];
}

/* Get the number of cells in a SafeArray */
static ULONG SAFEARRAY_GetCellCount(const SAFEARRAY *psa)
{
  const SAFEARRAYBOUND* psab = psa->rgsabound;
  USHORT cCount = psa->cDims;
  ULONG ulNumCells = 1;

  while (cCount--)
  {
    /* This is a valid bordercase. See testcases. -Marcus */
    if (!psab->cElements)
      return 0;
    ulNumCells *= psab->cElements;
    psab++;
  }
  return ulNumCells;
}

/* Allocate a descriptor for an array */
static HRESULT SAFEARRAY_AllocDescriptor(ULONG ulSize, SAFEARRAY **ppsaOut)
{
  char *ptr = SAFEARRAY_Malloc(ulSize + SAFEARRAY_HIDDEN_SIZE);

  if (!ptr)
  {
      *ppsaOut = NULL;
      return E_UNEXPECTED;
  }

  *ppsaOut = (SAFEARRAY*)(ptr + SAFEARRAY_HIDDEN_SIZE);
  return S_OK;
}

/* Set the features of an array */
static void SAFEARRAY_SetFeatures(VARTYPE vt, SAFEARRAY *psa)
{
  /* Set the IID if we have one, otherwise set the type */
  if (vt == VT_DISPATCH)
  {
    psa->fFeatures = FADF_HAVEIID;
    SafeArraySetIID(psa, &IID_IDispatch);
  }
  else if (vt == VT_UNKNOWN)
  {
    psa->fFeatures = FADF_HAVEIID;
    SafeArraySetIID(psa, &IID_IUnknown);
  }
  else if (vt == VT_RECORD)
    psa->fFeatures = FADF_RECORD;
  else
  {
    psa->fFeatures = FADF_HAVEVARTYPE;
    SAFEARRAY_SetHiddenDWORD(psa, vt);
  }
}

/* Create an array */
static SAFEARRAY* SAFEARRAY_Create(VARTYPE vt, UINT cDims, const SAFEARRAYBOUND *rgsabound, ULONG ulSize)
{
  SAFEARRAY *psa = NULL;
  unsigned int i;

  if (!rgsabound)
    return NULL;

  if (SUCCEEDED(SafeArrayAllocDescriptorEx(vt, cDims, &psa)))
  {
    switch (vt)
    {
      case VT_BSTR:     psa->fFeatures |= FADF_BSTR; break;
      case VT_UNKNOWN:  psa->fFeatures |= FADF_UNKNOWN; break;
      case VT_DISPATCH: psa->fFeatures |= FADF_DISPATCH; break;
      case VT_VARIANT:  psa->fFeatures |= FADF_VARIANT; break;
    }

    for (i = 0; i < cDims; i++)
      memcpy(psa->rgsabound + i, rgsabound + cDims - 1 - i, sizeof(SAFEARRAYBOUND));

    if (ulSize)
      psa->cbElements = ulSize;

    if (!psa->cbElements || FAILED(SafeArrayAllocData(psa)))
    {
      SafeArrayDestroyDescriptor(psa);
      psa = NULL;
    }
  }
  return psa;
}

/* Create an array as a vector */
static SAFEARRAY* SAFEARRAY_CreateVector(VARTYPE vt, LONG lLbound, ULONG cElements, ULONG ulSize)
{
  SAFEARRAY *psa = NULL;

  if (ulSize || (vt == VT_RECORD))
  {
    /* Allocate the header and data together */
    if (SUCCEEDED(SAFEARRAY_AllocDescriptor(sizeof(SAFEARRAY) + ulSize * cElements, &psa)))
    {
      SAFEARRAY_SetFeatures(vt, psa);

      psa->cDims = 1;
      psa->fFeatures |= FADF_CREATEVECTOR;
      psa->pvData = &psa[1]; /* Data follows the header */
      psa->cbElements = ulSize;
      psa->rgsabound[0].cElements = cElements;
      psa->rgsabound[0].lLbound = lLbound;

      switch (vt)
      {
        case VT_BSTR:     psa->fFeatures |= FADF_BSTR; break;
        case VT_UNKNOWN:  psa->fFeatures |= FADF_UNKNOWN; break;
        case VT_DISPATCH: psa->fFeatures |= FADF_DISPATCH; break;
        case VT_VARIANT:  psa->fFeatures |= FADF_VARIANT; break;
      }
    }
  }
  return psa;
}

/* Free data items in an array */
static HRESULT SAFEARRAY_DestroyData(SAFEARRAY *psa, ULONG ulStartCell)
{
  if (psa->pvData && !(psa->fFeatures & FADF_DATADELETED))
  {
    ULONG ulCellCount = SAFEARRAY_GetCellCount(psa);

    if (ulStartCell > ulCellCount) {
      FIXME("unexpted ulcellcount %d, start %d\n",ulCellCount,ulStartCell);
      return E_UNEXPECTED;
    }

    ulCellCount -= ulStartCell;

    if (psa->fFeatures & (FADF_UNKNOWN|FADF_DISPATCH))
    {
      LPUNKNOWN *lpUnknown = (LPUNKNOWN *)psa->pvData + ulStartCell;

      while(ulCellCount--)
      {
        if (*lpUnknown)
          IUnknown_Release(*lpUnknown);
        lpUnknown++;
      }
    }
    else if (psa->fFeatures & (FADF_RECORD))
    {
      IRecordInfo *lpRecInfo;

      if (SUCCEEDED(SafeArrayGetRecordInfo(psa, &lpRecInfo)))
      {
        PBYTE pRecordData = psa->pvData;
        while(ulCellCount--)
        {
          IRecordInfo_RecordClear(lpRecInfo, pRecordData);
          pRecordData += psa->cbElements;
        }
        IRecordInfo_Release(lpRecInfo);
      }
    }
    else if (psa->fFeatures & FADF_BSTR)
    {
      BSTR* lpBstr = (BSTR*)psa->pvData + ulStartCell;

      while(ulCellCount--)
      {
        SysFreeString(*lpBstr);
        lpBstr++;
      }
    }
    else if (psa->fFeatures & FADF_VARIANT)
    {
      VARIANT* lpVariant = (VARIANT*)psa->pvData + ulStartCell;

      while(ulCellCount--)
      {
        HRESULT hRet = VariantClear(lpVariant);

        if (FAILED(hRet)) FIXME("VariantClear of element failed!\n");
        lpVariant++;
      }
    }
  }
  return S_OK;
}

/* Copy data items from one array to another */
static HRESULT SAFEARRAY_CopyData(SAFEARRAY *psa, SAFEARRAY *dest)
{
  if (!psa->pvData)
    return S_OK;
  else if (!dest->pvData || psa->fFeatures & FADF_DATADELETED)
    return E_INVALIDARG;
  else
  {
    ULONG ulCellCount = SAFEARRAY_GetCellCount(psa);

    dest->fFeatures = (dest->fFeatures & FADF_CREATEVECTOR) |
                      (psa->fFeatures & ~(FADF_CREATEVECTOR|FADF_DATADELETED));

    if (psa->fFeatures & FADF_VARIANT)
    {
      VARIANT* lpVariant = psa->pvData;
      VARIANT* lpDest = dest->pvData;

      while(ulCellCount--)
      {
        HRESULT hRet;

        hRet = VariantCopy(lpDest, lpVariant);
        if (FAILED(hRet)) FIXME("VariantCopy failed with 0x%x\n", hRet);
        lpVariant++;
        lpDest++;
      }
    }
    else if (psa->fFeatures & FADF_BSTR)
    {
      BSTR* lpBstr = psa->pvData;
      BSTR* lpDest = dest->pvData;

      while(ulCellCount--)
      {
        if (*lpBstr)
        {
          *lpDest = SysAllocStringByteLen((char*)*lpBstr, SysStringByteLen(*lpBstr));
          if (!*lpDest)
            return E_OUTOFMEMORY;
        }
        else
          *lpDest = NULL;
        lpBstr++;
        lpDest++;
      }
    }
    else
    {
      /* Copy the data over */
      memcpy(dest->pvData, psa->pvData, ulCellCount * psa->cbElements);

      if (psa->fFeatures & (FADF_UNKNOWN|FADF_DISPATCH))
      {
        LPUNKNOWN *lpUnknown = dest->pvData;

        while(ulCellCount--)
        {
          if (*lpUnknown)
            IUnknown_AddRef(*lpUnknown);
          lpUnknown++;
        }
      }
    }

    if (psa->fFeatures & FADF_RECORD)
    {
      IRecordInfo* pRecInfo = NULL;

      SafeArrayGetRecordInfo(psa, &pRecInfo);
      SafeArraySetRecordInfo(dest, pRecInfo);

      if (pRecInfo)
      {
        /* Release because Get() adds a reference */
        IRecordInfo_Release(pRecInfo);
      }
    }
    else if (psa->fFeatures & FADF_HAVEIID)
    {
      GUID guid;
      SafeArrayGetIID(psa, &guid);
      SafeArraySetIID(dest, &guid);
    }
    else if (psa->fFeatures & FADF_HAVEVARTYPE)
    {
      SAFEARRAY_SetHiddenDWORD(dest, SAFEARRAY_GetHiddenDWORD(psa));
    }
  }
  return S_OK;
}

/*************************************************************************
 *		SafeArrayAllocDescriptor (OLEAUT32.36)
 *
 * Allocate and initialise a descriptor for a SafeArray.
 *
 * PARAMS
 *  cDims   [I] Number of dimensions of the array
 *  ppsaOut [O] Destination for new descriptor
 *
 * RETURNS
 * Success: S_OK. ppsaOut is filled with a newly allocated descriptor.
 * Failure: An HRESULT error code indicating the error.
 *
 * NOTES
 * See SafeArray.
 */
HRESULT WINAPI SafeArrayAllocDescriptor(UINT cDims, SAFEARRAY **ppsaOut)
{
  LONG allocSize;

  TRACE("(%d,%p)\n", cDims, ppsaOut);

  if (!cDims || cDims >= 0x10000) /* Maximum 65535 dimensions */
    return E_INVALIDARG;

  if (!ppsaOut)
    return E_POINTER;

  /* We need enough space for the header and its bounds */
  allocSize = sizeof(SAFEARRAY) + sizeof(SAFEARRAYBOUND) * (cDims - 1);

  if (FAILED(SAFEARRAY_AllocDescriptor(allocSize, ppsaOut)))
    return E_UNEXPECTED;

  (*ppsaOut)->cDims = cDims;

  TRACE("(%d): %u bytes allocated for descriptor.\n", cDims, allocSize);
  return S_OK;
}

/*************************************************************************
 *		SafeArrayAllocDescriptorEx (OLEAUT32.41)
 *
 * Allocate and initialise a descriptor for a SafeArray of a given type.
 *
 * PARAMS
 *  vt      [I] The type of items to store in the array
 *  cDims   [I] Number of dimensions of the array
 *  ppsaOut [O] Destination for new descriptor
 *
 * RETURNS
 *  Success: S_OK. ppsaOut is filled with a newly allocated descriptor.
 *  Failure: An HRESULT error code indicating the error.
 *
 * NOTES
 *  - This function does not check that vt is an allowed VARTYPE.
 *  - Unlike SafeArrayAllocDescriptor(), vt is associated with the array.
 *  See SafeArray.
 */
HRESULT WINAPI SafeArrayAllocDescriptorEx(VARTYPE vt, UINT cDims, SAFEARRAY **ppsaOut)
{
  ULONG cbElements;
  HRESULT hRet = E_UNEXPECTED;

  TRACE("(%d->%s,%d,%p)\n", vt, debugstr_vt(vt), cDims, ppsaOut);

  cbElements = SAFEARRAY_GetVTSize(vt);
  if (!cbElements)
    WARN("Creating a descriptor with an invalid VARTYPE!\n");

  hRet = SafeArrayAllocDescriptor(cDims, ppsaOut);

  if (SUCCEEDED(hRet))
  {
    SAFEARRAY_SetFeatures(vt, *ppsaOut);
    (*ppsaOut)->cbElements = cbElements;
  }
  return hRet;
}

/*************************************************************************
 *		SafeArrayAllocData (OLEAUT32.37)
 *
 * Allocate the data area of a SafeArray.
 *
 * PARAMS
 *  psa [I] SafeArray to allocate the data area of.
 *
 * RETURNS
 *  Success: S_OK. The data area is allocated and initialised.
 *  Failure: An HRESULT error code indicating the error.
 *
 * NOTES
 *  See SafeArray.
 */
HRESULT WINAPI SafeArrayAllocData(SAFEARRAY *psa)
{
  HRESULT hRet = E_INVALIDARG;

  TRACE("(%p)\n", psa);

  if (psa)
  {
    ULONG ulSize = SAFEARRAY_GetCellCount(psa);

    psa->pvData = SAFEARRAY_Malloc(ulSize * psa->cbElements);

    if (psa->pvData)
    {
      hRet = S_OK;
      TRACE("%u bytes allocated for data at %p (%u objects).\n",
            ulSize * psa->cbElements, psa->pvData, ulSize);
    }
    else
      hRet = E_OUTOFMEMORY;
  }
  return hRet;
}

/*************************************************************************
 *		SafeArrayCreate (OLEAUT32.15)
 *
 * Create a new SafeArray.
 *
 * PARAMS
 *  vt        [I] Type to store in the safe array
 *  cDims     [I] Number of array dimensions
 *  rgsabound [I] Bounds of the array dimensions
 *
 * RETURNS
 *  Success: A pointer to a new array object.
 *  Failure: NULL, if any parameter is invalid or memory allocation fails.
 *
 * NOTES
 *  Win32 allows arrays with 0 sized dimensions. This bug is not reproduced
 *  in the Wine implementation.
 *  See SafeArray.
 */
SAFEARRAY* WINAPI SafeArrayCreate(VARTYPE vt, UINT cDims, SAFEARRAYBOUND *rgsabound)
{
  TRACE("(%d->%s,%d,%p)\n", vt, debugstr_vt(vt), cDims, rgsabound);

  if (vt == VT_RECORD)
    return NULL;

  return SAFEARRAY_Create(vt, cDims, rgsabound, 0);
}

/*************************************************************************
 *		SafeArrayCreateEx (OLEAUT32.15)
 *
 * Create a new SafeArray.
 *
 * PARAMS
 *  vt        [I] Type to store in the safe array
 *  cDims     [I] Number of array dimensions
 *  rgsabound [I] Bounds of the array dimensions
 *  pvExtra   [I] Extra data
 *
 * RETURNS
 *  Success: A pointer to a new array object.
 *  Failure: NULL, if any parameter is invalid or memory allocation fails.
 *
 * NOTES
 * See SafeArray.
 */
SAFEARRAY* WINAPI SafeArrayCreateEx(VARTYPE vt, UINT cDims, SAFEARRAYBOUND *rgsabound, LPVOID pvExtra)
{
  ULONG ulSize = 0;
  IRecordInfo* iRecInfo = pvExtra;
  SAFEARRAY* psa;

  TRACE("(%d->%s,%d,%p,%p)\n", vt, debugstr_vt(vt), cDims, rgsabound, pvExtra);

  if (vt == VT_RECORD)
  {
    if  (!iRecInfo)
      return NULL;
    IRecordInfo_GetSize(iRecInfo, &ulSize);
  }
  psa = SAFEARRAY_Create(vt, cDims, rgsabound, ulSize);

  if (pvExtra)
  {
    switch(vt)
    {
      case VT_RECORD:
        SafeArraySetRecordInfo(psa, pvExtra);
        break;
      case VT_UNKNOWN:
      case VT_DISPATCH:
        SafeArraySetIID(psa, pvExtra);
        break;
    }
  }
  return psa;
}

/************************************************************************
 *		SafeArrayCreateVector (OLEAUT32.411)
 *
 * Create a one dimensional, contiguous SafeArray.
 *
 * PARAMS
 *  vt        [I] Type to store in the safe array
 *  lLbound   [I] Lower bound of the array
 *  cElements [I] Number of elements in the array
 *
 * RETURNS
 *  Success: A pointer to a new array object.
 *  Failure: NULL, if any parameter is invalid or memory allocation fails.
 *
 * NOTES
 * See SafeArray.
 */
SAFEARRAY* WINAPI SafeArrayCreateVector(VARTYPE vt, LONG lLbound, ULONG cElements)
{
  TRACE("(%d->%s,%d,%d\n", vt, debugstr_vt(vt), lLbound, cElements);

  if (vt == VT_RECORD)
    return NULL;

  return SAFEARRAY_CreateVector(vt, lLbound, cElements, SAFEARRAY_GetVTSize(vt));
}

/************************************************************************
 *		SafeArrayCreateVectorEx (OLEAUT32.411)
 *
 * Create a one dimensional, contiguous SafeArray.
 *
 * PARAMS
 *  vt        [I] Type to store in the safe array
 *  lLbound   [I] Lower bound of the array
 *  cElements [I] Number of elements in the array
 *  pvExtra   [I] Extra data
 *
 * RETURNS
 *  Success: A pointer to a new array object.
 *  Failure: NULL, if any parameter is invalid or memory allocation fails.
 *
 * NOTES
 * See SafeArray.
 */
SAFEARRAY* WINAPI SafeArrayCreateVectorEx(VARTYPE vt, LONG lLbound, ULONG cElements, LPVOID pvExtra)
{
  ULONG ulSize;
  IRecordInfo* iRecInfo = pvExtra;
  SAFEARRAY* psa;

 TRACE("(%d->%s,%d,%d,%p\n", vt, debugstr_vt(vt), lLbound, cElements, pvExtra);

  if (vt == VT_RECORD)
  {
    if  (!iRecInfo)
      return NULL;
    IRecordInfo_GetSize(iRecInfo, &ulSize);
  }
  else
    ulSize = SAFEARRAY_GetVTSize(vt);

  psa = SAFEARRAY_CreateVector(vt, lLbound, cElements, ulSize);

  if (pvExtra)
  {
    switch(vt)
    {
      case VT_RECORD:
        SafeArraySetRecordInfo(psa, iRecInfo);
        break;
      case VT_UNKNOWN:
      case VT_DISPATCH:
        SafeArraySetIID(psa, pvExtra);
        break;
    }
  }
  return psa;
}

/*************************************************************************
 *		SafeArrayDestroyDescriptor (OLEAUT32.38)
 *
 * Destroy a SafeArray.
 *
 * PARAMS
 *  psa [I] SafeArray to destroy.
 *
 * RETURNS
 *  Success: S_OK. The resources used by the array are freed.
 *  Failure: An HRESULT error code indicating the error.
 *
 * NOTES
 * See SafeArray.
 */
HRESULT WINAPI SafeArrayDestroyDescriptor(SAFEARRAY *psa)
{
  TRACE("(%p)\n", psa);

  if (psa)
  {
    LPVOID lpv = (char*)psa - SAFEARRAY_HIDDEN_SIZE;

    if (psa->cLocks)
      return DISP_E_ARRAYISLOCKED; /* Can't destroy a locked array */

    if (psa->fFeatures & FADF_RECORD)
      SafeArraySetRecordInfo(psa, NULL);

    if (psa->fFeatures & FADF_CREATEVECTOR &&
        !(psa->fFeatures & FADF_DATADELETED))
        SAFEARRAY_DestroyData(psa, 0); /* Data not previously deleted */

    if (!SAFEARRAY_Free(lpv))
      return E_UNEXPECTED;
  }
  return S_OK;
}

/*************************************************************************
 *		SafeArrayLock (OLEAUT32.21)
 *
 * Increment the lock counter of a SafeArray.
 *
 * PARAMS
 *  psa [O] SafeArray to lock
 *
 * RETURNS
 *  Success: S_OK. The array lock is incremented.
 *  Failure: E_INVALIDARG if psa is NULL, or E_UNEXPECTED if too many locks
 *           are held on the array at once.
 *
 * NOTES
 *  In Win32 these locks are not thread safe.
 *  See SafeArray.
 */
HRESULT WINAPI SafeArrayLock(SAFEARRAY *psa)
{
  ULONG ulLocks;

  TRACE("(%p)\n", psa);

  if (!psa)
    return E_INVALIDARG;

  ulLocks = InterlockedIncrement( (LONG*) &psa->cLocks);

  if (ulLocks > 0xffff) /* Maximum of 16384 locks at a time */
  {
    WARN("Out of locks!\n");
    InterlockedDecrement( (LONG*) &psa->cLocks);
    return E_UNEXPECTED;
  }
  return S_OK;
}

/*************************************************************************
 *		SafeArrayUnlock (OLEAUT32.22)
 *
 * Decrement the lock counter of a SafeArray.
 *
 * PARAMS
 *  psa [O] SafeArray to unlock
 *
 * RETURNS
 *  Success: S_OK. The array lock is decremented.
 *  Failure: E_INVALIDARG if psa is NULL, or E_UNEXPECTED if no locks are
 *           held on the array.
 *
 * NOTES
 * See SafeArray.
 */
HRESULT WINAPI SafeArrayUnlock(SAFEARRAY *psa)
{
  TRACE("(%p)\n", psa);

  if (!psa)
    return E_INVALIDARG;

  if (InterlockedDecrement( (LONG*) &psa->cLocks) < 0)
  {
    WARN("Unlocked but no lock held!\n");
    InterlockedIncrement( (LONG*) &psa->cLocks);
    return E_UNEXPECTED;
  }
  return S_OK;
}

/*************************************************************************
 *		SafeArrayPutElement (OLEAUT32.26)
 *
 * Put an item into a SafeArray.
 *
 * PARAMS
 *  psa       [I] SafeArray to insert into
 *  rgIndices [I] Indices to insert at
 *  pvData    [I] Data to insert
 *
 * RETURNS
 *  Success: S_OK. The item is inserted
 *  Failure: An HRESULT error code indicating the error.
 *
 * NOTES
 * See SafeArray.
 */
HRESULT WINAPI SafeArrayPutElement(SAFEARRAY *psa, LONG *rgIndices, void *pvData)
{
  HRESULT hRet;

  TRACE("(%p,%p,%p)\n", psa, rgIndices, pvData);

  if (!psa || !rgIndices)
    return E_INVALIDARG;

  hRet = SafeArrayLock(psa);

  if (SUCCEEDED(hRet))
  {
    PVOID lpvDest;

    hRet = SafeArrayPtrOfIndex(psa, rgIndices, &lpvDest);

    if (SUCCEEDED(hRet))
    {
      if (psa->fFeatures & FADF_VARIANT)
      {
        VARIANT* lpVariant = pvData;
        VARIANT* lpDest = lpvDest;

        hRet = VariantClear(lpDest);
        if (FAILED(hRet)) FIXME("VariantClear failed with 0x%x\n", hRet);
        hRet = VariantCopy(lpDest, lpVariant);
        if (FAILED(hRet)) FIXME("VariantCopy failed with 0x%x\n", hRet);
      }
      else if (psa->fFeatures & FADF_BSTR)
      {
        BSTR  lpBstr = (BSTR)pvData;
        BSTR* lpDest = lpvDest;

        SysFreeString(*lpDest);

        *lpDest = SysAllocStringByteLen((char*)lpBstr, SysStringByteLen(lpBstr));
        if (!*lpDest)
          hRet = E_OUTOFMEMORY;
      }
      else
      {
        if (psa->fFeatures & (FADF_UNKNOWN|FADF_DISPATCH))
        {
          LPUNKNOWN  lpUnknown = pvData;
          LPUNKNOWN *lpDest = lpvDest;

          if (lpUnknown)
            IUnknown_AddRef(lpUnknown);
          if (*lpDest)
            IUnknown_Release(*lpDest);
	  *lpDest = lpUnknown;
        } else {
          /* Copy the data over */
          memcpy(lpvDest, pvData, psa->cbElements);
	}
      }
    }
    SafeArrayUnlock(psa);
  }
  return hRet;
}

/*************************************************************************
 *		SafeArrayGetElement (OLEAUT32.25)
 *
 * Get an item from a SafeArray.
 *
 * PARAMS
 *  psa       [I] SafeArray to get from
 *  rgIndices [I] Indices to get from
 *  pvData    [O] Destination for data
 *
 * RETURNS
 *  Success: S_OK. The item data is returned in pvData.
 *  Failure: An HRESULT error code indicating the error.
 *
 * NOTES
 * See SafeArray.
 */
HRESULT WINAPI SafeArrayGetElement(SAFEARRAY *psa, LONG *rgIndices, void *pvData)
{
  HRESULT hRet;

  TRACE("(%p,%p,%p)\n", psa, rgIndices, pvData);

  if (!psa || !rgIndices || !pvData)
    return E_INVALIDARG;

  hRet = SafeArrayLock(psa);

  if (SUCCEEDED(hRet))
  {
    PVOID lpvSrc;

    hRet = SafeArrayPtrOfIndex(psa, rgIndices, &lpvSrc);

    if (SUCCEEDED(hRet))
    {
      if (psa->fFeatures & FADF_VARIANT)
      {
        VARIANT* lpVariant = lpvSrc;
        VARIANT* lpDest = pvData;

        /* The original content of pvData is ignored. */
        V_VT(lpDest) = VT_EMPTY;
        hRet = VariantCopy(lpDest, lpVariant);
	if (FAILED(hRet)) FIXME("VariantCopy failed with 0x%x\n", hRet);
      }
      else if (psa->fFeatures & FADF_BSTR)
      {
        BSTR* lpBstr = lpvSrc;
        BSTR* lpDest = pvData;

        if (*lpBstr)
        {
          *lpDest = SysAllocStringByteLen((char*)*lpBstr, SysStringByteLen(*lpBstr));
          if (!*lpBstr)
            hRet = E_OUTOFMEMORY;
        }
        else
          *lpDest = NULL;
      }
      else
      {
        if (psa->fFeatures & (FADF_UNKNOWN|FADF_DISPATCH))
        {
          LPUNKNOWN *lpUnknown = lpvSrc;

          if (*lpUnknown)
            IUnknown_AddRef(*lpUnknown);
        }
        /* Copy the data over */
        memcpy(pvData, lpvSrc, psa->cbElements);
      }
    }
    SafeArrayUnlock(psa);
  }
  return hRet;
}

/*************************************************************************
 *		SafeArrayGetUBound (OLEAUT32.19)
 *
 * Get the upper bound for a given SafeArray dimension
 *
 * PARAMS
 *  psa      [I] Array to get dimension upper bound from
 *  nDim     [I] The dimension number to get the upper bound of
 *  plUbound [O] Destination for the upper bound
 *
 * RETURNS
 *  Success: S_OK. plUbound contains the dimensions upper bound.
 *  Failure: An HRESULT error code indicating the error.
 *
 * NOTES
 * See SafeArray.
 */
HRESULT WINAPI SafeArrayGetUBound(SAFEARRAY *psa, UINT nDim, LONG *plUbound)
{
  TRACE("(%p,%d,%p)\n", psa, nDim, plUbound);

  if (!psa || !plUbound)
    return E_INVALIDARG;

  if(!nDim || nDim > psa->cDims)
    return DISP_E_BADINDEX;

  *plUbound = psa->rgsabound[psa->cDims - nDim].lLbound +
              psa->rgsabound[psa->cDims - nDim].cElements - 1;

  return S_OK;
}

/*************************************************************************
 *		SafeArrayGetLBound (OLEAUT32.20)
 *
 * Get the lower bound for a given SafeArray dimension
 *
 * PARAMS
 *  psa      [I] Array to get dimension lower bound from
 *  nDim     [I] The dimension number to get the lower bound of
 *  plLbound [O] Destination for the lower bound
 *
 * RETURNS
 *  Success: S_OK. plUbound contains the dimensions lower bound.
 *  Failure: An HRESULT error code indicating the error.
 *
 * NOTES
 * See SafeArray.
 */
HRESULT WINAPI SafeArrayGetLBound(SAFEARRAY *psa, UINT nDim, LONG *plLbound)
{
  TRACE("(%p,%d,%p)\n", psa, nDim, plLbound);

  if (!psa || !plLbound)
    return E_INVALIDARG;

  if(!nDim || nDim > psa->cDims)
    return DISP_E_BADINDEX;

  *plLbound = psa->rgsabound[psa->cDims - nDim].lLbound;
  return S_OK;
}

/*************************************************************************
 *		SafeArrayGetDim (OLEAUT32.17)
 *
 * Get the number of dimensions in a SafeArray.
 *
 * PARAMS
 *  psa [I] Array to get the dimensions of
 *
 * RETURNS
 *  The number of array dimensions in psa, or 0 if psa is NULL.
 *
 * NOTES
 * See SafeArray.
 */
UINT WINAPI SafeArrayGetDim(SAFEARRAY *psa)
{
  TRACE("(%p) returning %d\n", psa, psa ? psa->cDims : 0u);
  return psa ? psa->cDims : 0;
}

/*************************************************************************
 *		SafeArrayGetElemsize (OLEAUT32.18)
 *
 * Get the size of an element in a SafeArray.
 *
 * PARAMS
 *  psa [I] Array to get the element size from
 *
 * RETURNS
 *  The size of a single element in psa, or 0 if psa is NULL.
 *
 * NOTES
 * See SafeArray.
 */
UINT WINAPI SafeArrayGetElemsize(SAFEARRAY *psa)
{
  TRACE("(%p) returning %d\n", psa, psa ? psa->cbElements : 0u);
  return psa ? psa->cbElements : 0;
}

/*************************************************************************
 *		SafeArrayAccessData (OLEAUT32.23)
 *
 * Lock a SafeArray and return a pointer to its data.
 *
 * PARAMS
 *  psa     [I] Array to get the data pointer from
 *  ppvData [O] Destination for the arrays data pointer
 *
 * RETURNS
 *  Success: S_OK. ppvData contains the arrays data pointer, and the array
 *           is locked.
 *  Failure: An HRESULT error code indicating the error.
 *
 * NOTES
 * See SafeArray.
 */
HRESULT WINAPI SafeArrayAccessData(SAFEARRAY *psa, void **ppvData)
{
  TRACE("(%p,%p)\n", psa, ppvData);

  if(!psa || !ppvData)
    return E_INVALIDARG;

  if (SUCCEEDED(SafeArrayLock(psa)))
  {
    *ppvData = psa->pvData;
    return S_OK;
  }
  *ppvData = NULL;
  return E_UNEXPECTED;
}

/*************************************************************************
 *		SafeArrayUnaccessData (OLEAUT32.24)
 *
 * Unlock a SafeArray after accessing its data.
 *
 * PARAMS
 *  psa     [I] Array to unlock
 *
 * RETURNS
 *  Success: S_OK. The array is unlocked.
 *  Failure: An HRESULT error code indicating the error.
 *
 * NOTES
 * See SafeArray.
 */
HRESULT WINAPI SafeArrayUnaccessData(SAFEARRAY *psa)
{
  TRACE("(%p)\n", psa);
  return SafeArrayUnlock(psa);
}

/************************************************************************
 *		SafeArrayPtrOfIndex (OLEAUT32.148)
 *
 * Get the address of an item in a SafeArray.
 *
 * PARAMS
 *  psa       [I] Array to get the items address from
 *  rgIndices [I] Index of the item in the array
 *  ppvData   [O] Destination for item address
 *
 * RETURNS
 *  Success: S_OK. ppvData contains a pointer to the item.
 *  Failure: An HRESULT error code indicating the error.
 *
 * NOTES
 *  This function does not lock the array.
 *
 * NOTES
 * See SafeArray.
 */
HRESULT WINAPI SafeArrayPtrOfIndex(SAFEARRAY *psa, LONG *rgIndices, void **ppvData)
{
  USHORT dim;
  ULONG cell = 0, dimensionSize = 1;
  SAFEARRAYBOUND* psab;
  LONG c1;

  TRACE("(%p,%p,%p)\n", psa, rgIndices, ppvData);

  /* The general formula for locating the cell number of an entry in an n
   * dimensional array (where cn = coordinate in dimension dn) is:
   *
   * c1 + c2 * sizeof(d1) + c3 * sizeof(d2) ... + cn * sizeof(c(n-1))
   *
   * We calculate the size of the last dimension at each step through the
   * dimensions to avoid recursing to calculate the last dimensions size.
   */
  if (!psa || !rgIndices || !ppvData)
    return E_INVALIDARG;

  psab = psa->rgsabound + psa->cDims - 1;
  c1 = *rgIndices++;

  if (c1 < psab->lLbound || c1 >= psab->lLbound + (LONG)psab->cElements)
    return DISP_E_BADINDEX; /* Initial index out of bounds */

  for (dim = 1; dim < psa->cDims; dim++)
  {
    dimensionSize *= psab->cElements;

    psab--;

    if (!psab->cElements ||
        *rgIndices < psab->lLbound ||
        *rgIndices >= psab->lLbound + (LONG)psab->cElements)
    return DISP_E_BADINDEX; /* Index out of bounds */

    cell += (*rgIndices - psab->lLbound) * dimensionSize;
    rgIndices++;
  }

  cell += (c1 - psa->rgsabound[psa->cDims - 1].lLbound);

  *ppvData = (char*)psa->pvData + cell * psa->cbElements;
  return S_OK;
}

/************************************************************************
 *		SafeArrayDestroyData (OLEAUT32.39)
 *
 * Destroy the data associated with a SafeArray.
 *
 * PARAMS
 *  psa [I] Array to delete the data from
 *
 * RETURNS
 *  Success: S_OK. All items and the item data are freed.
 *  Failure: An HRESULT error code indicating the error.
 *
 * NOTES
 * See SafeArray.
 */
HRESULT WINAPI SafeArrayDestroyData(SAFEARRAY *psa)
{
  TRACE("(%p)\n", psa);

  if (!psa)
    return E_INVALIDARG;

  if (psa->cLocks)
    return DISP_E_ARRAYISLOCKED; /* Can't delete a locked array */

  /* Delete the actual item data */
  if (FAILED(SAFEARRAY_DestroyData(psa, 0)))
    return E_UNEXPECTED;

  if (psa->pvData)
  {
    if (psa->fFeatures & FADF_STATIC)
    {
      ZeroMemory(psa->pvData, SAFEARRAY_GetCellCount(psa) * psa->cbElements);
      return S_OK;
    }
    /* If this is not a vector, free the data memory block */
    if (!(psa->fFeatures & FADF_CREATEVECTOR))
    {
      if (!SAFEARRAY_Free(psa->pvData))
        return E_UNEXPECTED;
      psa->pvData = NULL;
    }
    else
      psa->fFeatures |= FADF_DATADELETED; /* Mark the data deleted */

  }
  return S_OK;
}

/************************************************************************
 *		SafeArrayCopyData (OLEAUT32.412)
 *
 * Copy all data from one SafeArray to another.
 *
 * PARAMS
 *  psaSource [I] Source for copy
 *  psaTarget [O] Destination for copy
 *
 * RETURNS
 *  Success: S_OK. psaTarget contains a copy of psaSource.
 *  Failure: An HRESULT error code indicating the error.
 *
 * NOTES
 *  The two arrays must have the same number of dimensions and elements.
 *
 * NOTES
 * See SafeArray.
 */
HRESULT WINAPI SafeArrayCopyData(SAFEARRAY *psaSource, SAFEARRAY *psaTarget)
{
  int dim;

  TRACE("(%p,%p)\n", psaSource, psaTarget);

  if (!psaSource || !psaTarget ||
      psaSource->cDims != psaTarget->cDims ||
      psaSource->cbElements != psaTarget->cbElements)
    return E_INVALIDARG;

  /* Each dimension must be the same size */
  for (dim = psaSource->cDims - 1; dim >= 0 ; dim--)
    if (psaSource->rgsabound[dim].cElements !=
       psaTarget->rgsabound[dim].cElements)
      return E_INVALIDARG;

  if (SUCCEEDED(SAFEARRAY_DestroyData(psaTarget, 0)) &&
      SUCCEEDED(SAFEARRAY_CopyData(psaSource, psaTarget)))
    return S_OK;
  return E_UNEXPECTED;
}

/************************************************************************
 *		SafeArrayDestroy (OLEAUT32.16)
 *
 * Destroy a SafeArray.
 *
 * PARAMS
 *  psa [I] Array to destroy
 *
 * RETURNS
 *  Success: S_OK. All resources used by the array are freed.
 *  Failure: An HRESULT error code indicating the error.
 *
 * NOTES
 * See SafeArray.
 */
HRESULT WINAPI SafeArrayDestroy(SAFEARRAY *psa)
{
  TRACE("(%p)\n", psa);

  if(!psa)
    return S_OK;

  if(psa->cLocks > 0)
    return DISP_E_ARRAYISLOCKED;

  /* Native doesn't check to see if the free succeeds */
  SafeArrayDestroyData(psa);
  SafeArrayDestroyDescriptor(psa);
  return S_OK;
}

/************************************************************************
 *		SafeArrayCopy (OLEAUT32.27)
 *
 * Make a duplicate of a SafeArray.
 *
 * PARAMS
 *  psa     [I] Source for copy
 *  ppsaOut [O] Destination for new copy
 *
 * RETURNS
 *  Success: S_OK. ppsaOut contains a copy of the array.
 *  Failure: An HRESULT error code indicating the error.
 *
 * NOTES
 * See SafeArray.
 */
HRESULT WINAPI SafeArrayCopy(SAFEARRAY *psa, SAFEARRAY **ppsaOut)
{
  HRESULT hRet;

  TRACE("(%p,%p)\n", psa, ppsaOut);

  if (!ppsaOut)
    return E_INVALIDARG;

  *ppsaOut = NULL;

  if (!psa)
    return S_OK; /* Handles copying of NULL arrays */

  if (!psa->cbElements)
    return E_INVALIDARG;

  if (psa->fFeatures & (FADF_RECORD|FADF_HAVEIID|FADF_HAVEVARTYPE))
  {
    VARTYPE vt;
    if (FAILED(SafeArrayGetVartype(psa, &vt)))
      hRet = E_UNEXPECTED;
    else
      hRet = SafeArrayAllocDescriptorEx(vt, psa->cDims, ppsaOut);
  }
  else
  {
    hRet = SafeArrayAllocDescriptor(psa->cDims, ppsaOut);
    if (SUCCEEDED(hRet))
    {
      (*ppsaOut)->fFeatures = psa->fFeatures & ~FADF_CREATEVECTOR;
      (*ppsaOut)->cbElements = psa->cbElements;
    }
  }

  if (SUCCEEDED(hRet))
  {
    /* Copy dimension bounds */
    memcpy((*ppsaOut)->rgsabound, psa->rgsabound, psa->cDims * sizeof(SAFEARRAYBOUND));

    (*ppsaOut)->pvData = SAFEARRAY_Malloc(SAFEARRAY_GetCellCount(psa) * psa->cbElements);

    if ((*ppsaOut)->pvData)
    {
      hRet = SAFEARRAY_CopyData(psa, *ppsaOut);

      if (SUCCEEDED(hRet))
        return hRet;

      SAFEARRAY_Free((*ppsaOut)->pvData);
    }
    SafeArrayDestroyDescriptor(*ppsaOut);
  }
  *ppsaOut = NULL;
  return hRet;
}

/************************************************************************
 *		SafeArrayRedim (OLEAUT32.40)
 *
 * Changes the characteristics of the last dimension of a SafeArray
 *
 * PARAMS
 *  psa      [I] Array to change
 *  psabound [I] New bound details for the last dimension
 *
 * RETURNS
 *  Success: S_OK. psa is updated to reflect the new bounds.
 *  Failure: An HRESULT error code indicating the error.
 *
 * NOTES
 * See SafeArray.
 */
HRESULT WINAPI SafeArrayRedim(SAFEARRAY *psa, SAFEARRAYBOUND *psabound)
{
  SAFEARRAYBOUND *oldBounds;

  TRACE("(%p,%p)\n", psa, psabound);

  if (!psa || psa->fFeatures & FADF_FIXEDSIZE || !psabound)
    return E_INVALIDARG;

  if (psa->cLocks > 0)
    return DISP_E_ARRAYISLOCKED;

  if (FAILED(SafeArrayLock(psa)))
    return E_UNEXPECTED;

  oldBounds = psa->rgsabound;
  oldBounds->lLbound = psabound->lLbound;

  if (psabound->cElements != oldBounds->cElements)
  {
    if (psabound->cElements < oldBounds->cElements)
    {
      /* Shorten the final dimension. */
      ULONG ulStartCell = psabound->cElements *
                          (SAFEARRAY_GetCellCount(psa) / oldBounds->cElements);
      SAFEARRAY_DestroyData(psa, ulStartCell);
    }
    else
    {
      /* Lengthen the final dimension */
      ULONG ulOldSize, ulNewSize;
      PVOID pvNewData;

      ulOldSize = SAFEARRAY_GetCellCount(psa) * psa->cbElements;
      if (ulOldSize)
        ulNewSize = (ulOldSize / oldBounds->cElements) * psabound->cElements;
      else {
	int oldelems = oldBounds->cElements;
	oldBounds->cElements = psabound->cElements;
        ulNewSize = SAFEARRAY_GetCellCount(psa) * psa->cbElements;
	oldBounds->cElements = oldelems;
      }

      if (!(pvNewData = SAFEARRAY_Malloc(ulNewSize)))
      {
        SafeArrayUnlock(psa);
        return E_UNEXPECTED;
      }

      memcpy(pvNewData, psa->pvData, ulOldSize);
      SAFEARRAY_Free(psa->pvData);
      psa->pvData = pvNewData;
    }
    oldBounds->cElements = psabound->cElements;
  }

  SafeArrayUnlock(psa);
  return S_OK;
}

/************************************************************************
 *		SafeArrayGetVartype (OLEAUT32.77)
 *
 * Get the type of the items in a SafeArray.
 *
 * PARAMS
 *  psa [I] Array to get the type from
 *  pvt [O] Destination for the type
 *
 * RETURNS
 *  Success: S_OK. pvt contains the type of the items.
 *  Failure: An HRESULT error code indicating the error.
 *
 * NOTES
 * See SafeArray.
 */
HRESULT WINAPI SafeArrayGetVartype(SAFEARRAY* psa, VARTYPE* pvt)
{
  TRACE("(%p,%p)\n", psa, pvt);

  if (!psa || !pvt)
    return E_INVALIDARG;

  if (psa->fFeatures & FADF_RECORD)
    *pvt = VT_RECORD;
  else if ((psa->fFeatures & (FADF_HAVEIID|FADF_DISPATCH)) == (FADF_HAVEIID|FADF_DISPATCH))
    *pvt = VT_DISPATCH;
  else if (psa->fFeatures & FADF_HAVEIID)
    *pvt = VT_UNKNOWN;
  else if (psa->fFeatures & FADF_HAVEVARTYPE)
  {
    VARTYPE vt = SAFEARRAY_GetHiddenDWORD(psa);
    *pvt = vt;
  }
  else
    return E_INVALIDARG;

  return S_OK;
}

/************************************************************************
 *		SafeArraySetRecordInfo (OLEAUT32.@)
 *
 * Set the record info for a SafeArray.
 *
 * PARAMS
 *  psa    [I] Array to set the record info for
 *  pRinfo [I] Record info
 *
 * RETURNS
 *  Success: S_OK. The record info is stored with the array.
 *  Failure: An HRESULT error code indicating the error.
 *
 * NOTES
 * See SafeArray.
 */
HRESULT WINAPI SafeArraySetRecordInfo(SAFEARRAY *psa, IRecordInfo *pRinfo)
{
  IRecordInfo** dest = (IRecordInfo**)psa;

  TRACE("(%p,%p)\n", psa, pRinfo);

  if (!psa || !(psa->fFeatures & FADF_RECORD))
    return E_INVALIDARG;

  if (pRinfo)
    IRecordInfo_AddRef(pRinfo);

  if (dest[-1])
    IRecordInfo_Release(dest[-1]);

  dest[-1] = pRinfo;
  return S_OK;
}

/************************************************************************
 *		SafeArrayGetRecordInfo (OLEAUT32.@)
 *
 * Get the record info from a SafeArray.
 *
 * PARAMS
 *  psa    [I] Array to get the record info from
 *  pRinfo [O] Destination for the record info
 *
 * RETURNS
 *  Success: S_OK. pRinfo contains the record info, or NULL if there was none.
 *  Failure: An HRESULT error code indicating the error.
 *
 * NOTES
 * See SafeArray.
 */
HRESULT WINAPI SafeArrayGetRecordInfo(SAFEARRAY *psa, IRecordInfo **pRinfo)
{
  IRecordInfo** src = (IRecordInfo**)psa;

  TRACE("(%p,%p)\n", psa, pRinfo);

  if (!psa || !pRinfo || !(psa->fFeatures & FADF_RECORD))
    return E_INVALIDARG;

  *pRinfo = src[-1];

  if (*pRinfo)
    IRecordInfo_AddRef(*pRinfo);
  return S_OK;
}

/************************************************************************
 *		SafeArraySetIID (OLEAUT32.@)
 *
 * Set the IID for a SafeArray.
 *
 * PARAMS
 *  psa  [I] Array to set the IID from
 *  guid [I] IID
 *
 * RETURNS
 *  Success: S_OK. The IID is stored with the array
 *  Failure: An HRESULT error code indicating the error.
 *
 * NOTES
 * See SafeArray.
 */
HRESULT WINAPI SafeArraySetIID(SAFEARRAY *psa, REFGUID guid)
{
  GUID* dest = (GUID*)psa;

  TRACE("(%p,%s)\n", psa, debugstr_guid(guid));

  if (!psa || !guid || !(psa->fFeatures & FADF_HAVEIID))
    return E_INVALIDARG;

  dest[-1] = *guid;
  return S_OK;
}

/************************************************************************
 *		SafeArrayGetIID (OLEAUT32.@)
 *
 * Get the IID from a SafeArray.
 *
 * PARAMS
 *  psa   [I] Array to get the ID from
 *  pGuid [O] Destination for the IID
 *
 * RETURNS
 *  Success: S_OK. pRinfo contains the IID, or NULL if there was none.
 *  Failure: An HRESULT error code indicating the error.
 *
 * NOTES
 * See SafeArray.
 */
HRESULT WINAPI SafeArrayGetIID(SAFEARRAY *psa, GUID *pGuid)
{
  GUID* src = (GUID*)psa;

  TRACE("(%p,%p)\n", psa, pGuid);

  if (!psa || !pGuid || !(psa->fFeatures & FADF_HAVEIID))
    return E_INVALIDARG;

  *pGuid = src[-1];
  return S_OK;
}

/************************************************************************
 *		VectorFromBstr (OLEAUT32.@)
 *
 * Create a SafeArray Vector from the bytes of a BSTR.
 *
 * PARAMS
 *  bstr [I] String to get bytes from
 *  ppsa [O] Destination for the array
 *
 * RETURNS
 *  Success: S_OK. ppsa contains the strings bytes as a VT_UI1 array.
 *  Failure: An HRESULT error code indicating the error.
 *
 * NOTES
 * See SafeArray.
 */
HRESULT WINAPI VectorFromBstr(BSTR bstr, SAFEARRAY **ppsa)
{
  SAFEARRAYBOUND sab;

  TRACE("(%p,%p)\n", bstr, ppsa);

  if (!ppsa)
    return E_INVALIDARG;

  sab.lLbound = 0;
  sab.cElements = SysStringByteLen(bstr);

  *ppsa = SAFEARRAY_Create(VT_UI1, 1, &sab, 0);

  if (*ppsa)
  {
    memcpy((*ppsa)->pvData, bstr, sab.cElements);
    return S_OK;
  }
  return E_OUTOFMEMORY;
}

/************************************************************************
 *		BstrFromVector (OLEAUT32.@)
 *
 * Create a BSTR from a SafeArray.
 *
 * PARAMS
 *  psa   [I] Source array
 *  pbstr [O] Destination for output BSTR
 *
 * RETURNS
 *  Success: S_OK. pbstr contains the arrays data.
 *  Failure: An HRESULT error code indicating the error.
 *
 * NOTES
 *  psa must be a 1 dimensional array of a 1 byte type.
 *
 * NOTES
 * See SafeArray.
 */
HRESULT WINAPI BstrFromVector(SAFEARRAY *psa, BSTR *pbstr)
{
  TRACE("(%p,%p)\n", psa, pbstr);

  if (!pbstr)
    return E_INVALIDARG;

  *pbstr = NULL;

  if (!psa || psa->cbElements != 1 || psa->cDims != 1)
    return E_INVALIDARG;

  *pbstr = SysAllocStringByteLen(psa->pvData, psa->rgsabound[0].cElements);
  if (!*pbstr)
    return E_OUTOFMEMORY;
  return S_OK;
}


text:
namespace Umbraco.Core.Configuration.UmbracoSettings
{
    public interface IWebRoutingSection : IUmbracoConfigurationSection
    {
        bool TrySkipIisCustomErrors { get; }

        bool InternalRedirectPreservesTemplate { get; }

        string UrlProviderMode { get; }
    }

}

redpajama_set_name: RedPajamaGithub


text:
<?php
/**
 * HTML cache invalidation of all pages linking to a given title.
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License along
 * with this program; if not, write to the Free Software Foundation, Inc.,
 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
 * http://www.gnu.org/copyleft/gpl.html
 *
 * @file
 * @ingroup JobQueue
 * @ingroup Cache
 */

/**
 * Job to purge the cache for all pages that link to or use another page or file
 *
 * This job comes in a few variants:
 *   - a) Recursive jobs to purge caches for backlink pages for a given title.
 *        These jobs have (recursive:true,table:<table>) set.
 *   - b) Jobs to purge caches for a set of titles (the job title is ignored).
 *	      These jobs have (pages:(<page ID>:(<namespace>,<title>),...) set.
 *
 * @ingroup JobQueue
 */
class HTMLCacheUpdateJob extends Job {
	function __construct( Title $title, array $params ) {
		parent::__construct( 'htmlCacheUpdate', $title, $params );
		// Base backlink purge jobs can be de-duplicated
		$this->removeDuplicates = ( !isset( $params['range'] ) && !isset( $params['pages'] ) );
	}

	function run() {
		global $wgUpdateRowsPerJob, $wgUpdateRowsPerQuery;

		if ( isset( $this->params['table'] ) && !isset( $this->params['pages'] ) ) {
			$this->params['recursive'] = true; // b/c; base job
		}

		// Job to purge all (or a range of) backlink pages for a page
		if ( !empty( $this->params['recursive'] ) ) {
			// Convert this into no more than $wgUpdateRowsPerJob HTMLCacheUpdateJob per-title
			// jobs and possibly a recursive HTMLCacheUpdateJob job for the rest of the backlinks
			$jobs = BacklinkJobUtils::partitionBacklinkJob(
				$this,
				$wgUpdateRowsPerJob,
				$wgUpdateRowsPerQuery, // jobs-per-title
				// Carry over information for de-duplication
				array( 'params' => $this->getRootJobParams() )
			);
			JobQueueGroup::singleton()->push( $jobs );
		// Job to purge pages for a set of titles
		} elseif ( isset( $this->params['pages'] ) ) {
			$this->invalidateTitles( $this->params['pages'] );
		// Job to update a single title
		} else {
			$t = $this->title;
			$this->invalidateTitles( array(
				$t->getArticleID() => array( $t->getNamespace(), $t->getDBkey() )
			) );
		}

		return true;
	}

	/**
	 * @param array $pages Map of (page ID => (namespace, DB key)) entries
	 */
	protected function invalidateTitles( array $pages ) {
		global $wgUpdateRowsPerQuery, $wgUseFileCache, $wgUseSquid;

		// Get all page IDs in this query into an array
		$pageIds = array_keys( $pages );
		if ( !$pageIds ) {
			return;
		}

		$dbw = wfGetDB( DB_MASTER );

		// The page_touched field will need to be bumped for these pages.
		// Only bump it to the present time if no "rootJobTimestamp" was known.
		// If it is known, it can be used instead, which avoids invalidating output
		// that was in fact generated *after* the relevant dependency change time
		// (e.g. template edit). This is particularily useful since refreshLinks jobs
		// save back parser output and usually run along side htmlCacheUpdate jobs;
		// their saved output would be invalidated by using the current timestamp.
		if ( isset( $this->params['rootJobTimestamp'] ) ) {
			$touchTimestamp = $this->params['rootJobTimestamp'];
		} else {
			$touchTimestamp = wfTimestampNow();
		}

		// Update page_touched (skipping pages already touched since the root job).
		// Check $wgUpdateRowsPerQuery for sanity; batch jobs are sized by that already.
		foreach ( array_chunk( $pageIds, $wgUpdateRowsPerQuery ) as $batch ) {
			$dbw->update( 'page',
				array( 'page_touched' => $dbw->timestamp( $touchTimestamp ) ),
				array( 'page_id' => $batch,
					// don't invalidated pages that were already invalidated
					"page_touched < " . $dbw->addQuotes( $dbw->timestamp( $touchTimestamp ) )
				),
				__METHOD__
			);
		}
		// Get the list of affected pages (races only mean something else did the purge)
		$titleArray = TitleArray::newFromResult( $dbw->select(
			'page',
			array( 'page_namespace', 'page_title' ),
			array( 'page_id' => $pageIds, 'page_touched' => $dbw->timestamp( $touchTimestamp ) ),
			__METHOD__
		) );

		// Update squid
		if ( $wgUseSquid ) {
			$u = SquidUpdate::newFromTitles( $titleArray );
			$u->doUpdate();
		}

		// Update file cache
		if ( $wgUseFileCache ) {
			foreach ( $titleArray as $title ) {
				HTMLFileCache::clearFileCache( $title );
			}
		}
	}

	public function workItemCount() {
		return isset( $this->params['pages'] ) ? count( $this->params['pages'] ) : 1;
	}
}


text:
void copy_command(void);
void process_command(void);
void print_value (char *id, int value);
void uart_ok(void);
int parse_assignment (char input[16]);
void process_uart(void);


text:
package com.lvxingpai.etcd

import com.google.inject.Injector

/**
 * 管理已有的Injector
 *
 * Created by zephyre on 11/18/15.
 */
object InjectorManager {
  private val injectorMap = scala.collection.mutable.Map[String, Injector]()

  def get(name: String): Option[Injector] = injectorMap.get(name)

  def put(name: String, injector: Injector): Unit = injectorMap.put(name, injector)
}


text:
{% extends "layout/default.html" %}

{% set active_page = 'publications' %}

{% block title %}
  Publications{{ super() }}
{% endblock %}

{% block main_body %}

      Publications

Mahlberg, M., Stockwell, P., de Joode, J., Smith, C., O'Donnell, M. Brook, (forthcoming 2016). CLiC Dickens – Novel uses of concordances for the integration of corpus stylistics and cognitive poetics, Corpora

Mahlberg, M. & Stockwell, P. (2016). Point and CLiC: teaching literature with corpus stylistic tools, in M. Burke et al. (eds.) Scientific Approaches to Literature in Learning Environments (pp. 251-267). Amsterdam: John Benjamins.

Mahlberg, M. (2016). Corpus Stylistics. In V. Sotirova (ed.) The Bloomsbury Companion to Stylistics. London & New York: Bloomsbury (pp. 139-156).

Mahlberg, M. (2015). Corpus Linguistics. In M. Giovanelli, A. Macrae, F. Titjen and I. Cushing (eds.) English Language and Literature. A/AS Level for AQA. 284-286.

Stockwell, P & Mahlberg, M. (2015). Mind-modelling with corpus stylistics in David Copperfield, Language and Literature, 24: 129-147. Link.

    {% include "blocks/twitter.html" %}

{% endblock %}

{% block scripts %}
  {{ super() }}
{% endblock %}


text:
===========
tempest-lib
===========

OpenStack Functional Testing Library

* Free software: Apache license
* Documentation: http://docs.openstack.org/developer/tempest-lib
* Source: http://git.openstack.org/cgit/openstack/tempest-lib
* Bugs: http://bugs.launchpad.net/tempest

tempest-lib is a library of common functionality that was originally in tempest
(or similar in scope to tempest)

Features
--------

Some of the current functionality exposed from the library includes:

* OpenStack python-* client CLI testing framework
* subunit-trace: A output filter for subunit streams. Useful in conjunction
                 with calling a test runner that emits subunit
* A unified REST Client
* Utility functions:
  * skip_because: Skip a test because of a bug
  * find_test_caller: Perform stack introspection to find the test caller.
                      common methods


text:
#include <cmath>
#include <iostream>
#include "Detector.h"
#include "SpecialFunctions.h"

using namespace std;

class GaussianDetector : public Detector {
public:

protected:
	double mu;
	double sigma;

	virtual void estimatePdfParameters(double* clutterValues, const int numberOfClutterValues)
	{
		mu = 0.0;
		sigma = 0.0;

		for(int i=0; i<numberOfClutterValues; i++) {
			mu += clutterValues[i];
			sigma += (clutterValues[i] * clutterValues[i]);
		}

		mu /= numberOfClutterValues;
		sigma /= (numberOfClutterValues - 1);
		sigma -= numberOfClutterValues * mu * mu / (numberOfClutterValues - 1);
		sigma = sqrt(sigma);
	}

	virtual double estimateThreshold(const double probabilityOfFalseAlarm)
	{
		return (1.414213562373095 * sigma * inverseCompErrorFunc(2 * probabilityOfFalseAlarm) + mu);
	}

private:

};


text:
package com.sample.greatfeat.adapter;

/**
 * Created by john.moratas on 6/20/2017.
 */

public class News {
    private String title, description, image;

    public News() {
    }

    public News(String title, String description, String image) {
        this.title = title;
        this.description = description;
        this.image = image;
    }

    public String getTitle() {
        return title;
    }

    public void setTitle(String name) {
        this.title = name;
    }

    public String getDescription() {
        return description;
    }

    public void setDescription(String description) {
        this.description = description;
    }

    public String getImage() {
        return image;
    }

    public void setImage(String image) {
        this.image = image;
    }

}


text:
Instead of requiring you to copy-paste large sections of workflows to perform
similar tasks, Daisy provides two different step types for workflow reuse:
`IncludeWorkflow` and `SubWorkflow`. Both step types will cause Daisy to run the
workflow they specify, but they differ slightly in how they share (or do not
share) resources.

### IncludeWorkflow

The parent workflow of a workflow included using `IncludeWorkflow` has access to
the child workflow's resources, and vice versa. Sources and named resources
(e.g. disks, instances) present in either workflow can be referenced by name
from either workflow. Two children with a common parent can also access each
other's resources. It is up to you to ensure there are no naming collisions
amongst included workflows and their parents.

`IncludeWorkflow` will run the steps of the included workflow in parallel with
the parent workflow's steps, according to the dependency rules of both the
parent and included workflows. A workflow included with `IncludeWorkflow` will
behave largely as if the included workflow had been copy-pasted into the parent
workflow.

See also the [documentation](daisy-workflow-config-spec.md#type-includeworkflow)
for IncludeWorkflow.

### SubWorkflow

`SubWorkflow` runs the subworkflow specified as one step. Subworkflows do not
have access to their parent's resources. This means that any workflow can be
used as a subworkflow without fear of resource name collisions. Additionally,
the subworkflow inherits its parent's `Project`, `Zone`, `GCSPath`, and
`OAuthPath` fields. Even if these fields are set in the subworkflow, they will
be overwritten with the parent's values.

See also the [documentation](daisy-workflow-config-spec.md#type-subworkflow) for
SubWorkflow.

## Using Vars

To allow parent workflows to control the behavior of their children, they can
set the `Vars` of a child workflow. Vars are represented by simple JSON objects
with three fields: `Value`, `Description`, and `Required`. Both
`IncludeWorkflow` and `SubWorkflow` tasks provide their own `Vars` field, which
allows the parent workflow to set the `Vars` of the child workflow. If a child
has a Var marked `Required` that is not set by the parent, an error will occur.

The typical use case for parent/child Vars is to set the `Required` and
`Description` of the child's Vars (but not the `Value`), and then pass values
from the parent. Here is an example of the child:

    {
      "Name": "child",
      "Vars": {
        "var1": { "Required": true, "Description": "passed from the parent" },
        "var2": { "Required": true, "Description": "also important" }
      },
      "Steps:" { ...  },
      "Dependencies": { ... }
    }

And the corresponding parent:

    {
      "Name": "parent",
      ...
      "Steps": {
        "include-step": {
          "IncludeWorkflow": {
            "Path": "path-to-child.wf.json",
            "Vars": {
              "var1": "value1",
              "var2": "value2"
            }
          }
        },
        ...
      },
      "Dependencies": { ... }
    }


text:
(function(f){if(typeof exports==="object"&&typeof module!=="undefined"){module.exports=f()}else if(typeof define==="function"&&define.amd){define([],f)}else{var g;if(typeof window!=="undefined"){g=window}else if(typeof global!=="undefined"){g=global}else if(typeof self!=="undefined"){g=self}else{g=this}g.Vizu = f()}})(function(){var define,module,exports;return (function(){function r(e,n,t){function o(i,f){if(!n[i]){if(!e[i]){var c="function"==typeof require&&require;if(!f&&c)return c(i,!0);if(u)return u(i,!0);var a=new Error("Cannot find module '"+i+"'");throw a.code="MODULE_NOT_FOUND",a}var p=n[i]={exports:{}};e[i][0].call(p.exports,function(r){var n=e[i][1][r];return o(n||r)},p,p.exports,r,e,n,t)}return n[i].exports}for(var u="function"==typeof require&&require,i=0;i<t.length;i++)o(t[i]);return o}return r})()({1:[function(require,module,exports){
"use strict";

Object.defineProperty(exports, "__esModule", {
  value: true
});
exports.default = void 0;

var _vizu = _interopRequireDefault(require("./src/vizu"));

var _component = _interopRequireDefault(require("./src/component"));

function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }

var _default = {
  Vizu: _vizu.default,
  Component: _component.default
};
exports.default = _default;
module.exports = exports.default;

},{"./src/component":2,"./src/vizu":6}],2:[function(require,module,exports){
"use strict";

Object.defineProperty(exports, "__esModule", {
  value: true
});
exports.default = void 0;

var _vizu = _interopRequireDefault(require("./vizu"));

var _animate = _interopRequireDefault(require("./private/animate"));

var _overslash = _interopRequireDefault(require("./private/overslash"));

function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }

function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }

function _defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } }

function _createClass(Constructor, protoProps, staticProps) { if (protoProps) _defineProperties(Constructor.prototype, protoProps); if (staticProps) _defineProperties(Constructor, staticProps); return Constructor; }

// -- Global constants (in the scope of this module)
// -- Public Methods -----------------------------------------------------------

/**
* This class defines the web component.
*
* @namespace vizu
*/
var Component =
/*#__PURE__*/
function () {
  /**
   * Creates an unique ID for this component.
   *
   * @constructor ()
   * @public
   * @param {}          -,
   */
  function Component() {
    _classCallCheck(this, Component);

    // Create an unique id for this component:
    this.id = "i".concat(Math.random().toString(36).substr(2, 7));
    this.cList = null;
    this.components = null;
    this.props = {};
    this.props.options = {};
  }
  /**
   * Initialises the variables when the component is rendered.
   *
   * @method ()
   * @public
   * @param {}        -,
   * @returns {}      -,
   * @since 0.0.0
   */

  _createClass(Component, [{
    key: "getInitialState",
    value: function getInitialState() {
      // To avoid eslint error!
      this.props = {};
      this.props.options = {};
    }
    /**
     * Returns the the first element that matches the specified CSS selector(s).
     *
     * @method (arg1)
     * @public
     * @param {String}    the CSS selector(s),
     * @returns {Object}  returns the first element that matches a specified
     *                    CSS selector(s),
     * @since 0.0.0
     */

  }, {
    key: "$",
    value: function $(selector) {
      var cid = this.id,
          docu = _vizu.default.vdom ? _vizu.default.vdom.window.document : document;
      var el;
      /**
       * Select a child element.
       *
       * @method (arg1)
       * @public
       * @param {String}    the selector,
       * @returns {Object}  returns this,
       * @since 0.0.8
       */

      var select = function select(sel) {
        if (typeof sel === 'string' && this[0]) {
          var child = this[0].querySelector(sel);

          if (child) {
            this[0] = child;
          }
        }

        return this;
      };
      /**
       * Selects the specified child if it exists.
       *
       * @method (arg1)
       * @public
       * @param {Number}    the child index,
       * @returns {Object}  returns this,
       * @since 0.0.8
       */

      var selectChild = function selectChild(n) {
        if (Object.prototype.toString.call(n) === '[object Number]') {
          this[0] = this[0].children[n] ? this[0].children[n] : this[0];
        }

        return this;
      };
      /**
       * Returns to the parent element.
       *
       * @method ()
       * @public
       * @param {}          -,
       * @returns {Object}  returns this,
       * @since 0.0.8
       */

      var parent = function parent() {
        if (this.root) {
          // As a root parent is defined, we stop at it.
          if (this[0] !== this.root) {
            this[0] = this[0].parentNode;
          }
        } else {
          this[0] = this[0].parentNode;
        }

        return this;
      };
      /**
       * Returns to the root parent if defined.
       *
       * @method ()
       * @public
       * @param {}          -,
       * @returns {Object}  returns this,
       * @since 0.0.7
       */

      var firstParent = function firstParent() {
        if (this.root) {
          this[0] = this.root;
        }

        return this;
      };
      /**
       * Gets/Sets the HTML contents of the element,
       *
       * @method (arg1)
       * @public
       * @param {String}    the html contents to add,
       * @returns {String}  returns the node DOMString or this,
       * @since 0.0.0
       */

      var html = function html(xmlString) {
        if (xmlString) {
          this[0].innerHTML = xmlString;
          return this;
        }

        return this[0].innerHTML;
      };
      /**
       * Removes all the childs of the current node.
       *
       * @method ()
       * @public
       * @param {}          -,
       * @returns {Object}  returns this,
       * @since 0.0.4
       */

      var empty = function empty() {
        while (this[0].firstChild) {
          this[0].removeChild(this[0].firstChild);
        }

        return this;
      };
      /**
       * Appends an HTML string after the last child of the current node.
       *
       * @method (arg1)
       * @public
       * @param {String}    an HTML string,
       * @returns {Object}  returns this,
       * @since 0.0.4
       */

      var append = function append(xmlString) {
        if (typeof xmlString === 'string') {
          this[0].insertAdjacentHTML('beforeend', xmlString);
        }

        return this;
      };
      /**
       * Appends an HTML string before the first child of the current node.
       *
       * @method (arg1)
       * @public
       * @param {String}    an HTML string,
       * @returns {Object}  returns this,
       * @since 0.0.6
       */

      var prepend = function prepend(xmlString) {
        if (typeof xmlString === 'string') {
          this[0].insertAdjacentHTML('afterbegin', xmlString);
        }

        return this;
      };
      /**
       * Appends an HTML string after the current node.
       *
       * Nota: this method adds a node after the current node only if it is
       * a child node of this component. 'after' is forbidden on the root node.
       *
       * @method (arg1)
       * @public
       * @param {String}    an HTML string,
       * @returns {Object}  returns this,
       * @since 0.0.6
       */

      var after = function after(xmlString) {
        if (typeof xmlString === 'string' && this[0].id !== cid) {
          this[0].insertAdjacentHTML('afterend', xmlString);
        }

        return this;
      };
      /**
       * Appends an HTML string before the current node.
       *
       * Nota: this method adds a node before the current node only if it is
       * a child node of this component. 'before' is forbidden on the root node.
       *
       * @method (arg1)
       * @public
       * @param {String}    an HTML string,
       * @returns {Object}  returns this,
       * @since 0.0.6
       */

      var before = function before(xmlString) {
        if (typeof xmlString === 'string' && this[0].id !== cid) {
          this[0].insertAdjacentHTML('beforebegin', xmlString);
        }

        return this;
      };
      /**
       * Replaces the current node with the given DOMString.
       *
       * Nota: this method replaces the current node only if it is
       * a child node of this component. 'replaceWith' is forbidden on the root node.
       *
       * @method (arg1)
       * @public
       * @param {String}    an HTML string,
       * @returns {Object}  returns this,
       * @since 0.0.6
       */

      var replaceWith = function replaceWith(xmlString) {
        var oldChild = this[0],
            parento = oldChild.parentNode // , index    =  Array.prototype.indexOf.call(parent.children, oldChild)
        ,
            wrapper = docu.createElement('div');
        var newChild;

        if (typeof xmlString === 'string' && oldChild.id !== cid) {
          // Replace the old child by new one:
          wrapper.innerHTML = xmlString;
          newChild = wrapper.firstChild;
          parento.replaceChild(newChild, oldChild);
        }

        return this;
      };
      /**
       * Gets/Sets the text contents of the element,
       *
       * @method (arg1)
       * @public
       * @param {String}    the text contents to add,
       * @returns {String}  returns the text contents or this;,
       * @since 0.0.0
       */

      var text = function text(texte) {
        if (texte) {
          this[0].textContent = texte;
          return this;
        }

        return this[0].textContent;
      };
      /**
       * Clones the selected element.
       *
       * @method (arg1)
       * @public
       * @param {Boolean}   true clone with children, false without,
       * @returns {Object}  returns the cloned element,
       * @since 0.0.8
       */

      var clone = function clone(deep) {
        if (deep === true || deep === false) {
          return this[0].cloneNode(deep);
        }

        return this[0].cloneNode(true);
      };
      /**
       * Inserts a child element before another child element.
       *
       * @method (arg1, arg2)
       * @public
       * @param {Object}    the new node element,
       * @param {Object}    the target node element,
       * @returns {Object}  returns this,
       * @since 0.0.8
       */

      var insertChildBefore = function insertChildBefore(newChild, child) {
        if (newChild) {
          this[0].insertBefore(newChild, child);
        }

        return this;
      };
      /**
       * Removed the passed-in child element.
       *
       * @method (arg1)
       * @public
       * @param {Object}    the child element to remove,
       * @returns {Object}  returns this,
       * @since 0.0.8
       */

      var removeChild = function removeChild(child) {
        if (child) {
          this[0].removeChild(child);
        }

        return this;
      };
      /**
       * Replaces a child by another.
       *
       * @method (arg1, arg2)
       * @public
       * @param {Object}    the new node element,
       * @param {Object}    the node element to replace,
       * @returns {Object}  returns this,
       * @since 0.0.8
       */

      var replaceChild = function replaceChild(newChild, child) {
        if (newChild) {
          this[0].replaceChild(newChild, child);
        }

        return this;
      };
      /**
       * Returns the children.
       *
       * @method ()
       * @public
       * @param {}          -,
       * @returns {Object}  returns the children HTMLCollection,
       * @since 0.0.8
       */

      var children = function children() {
        return this[0].children;
      };
      /**
       * Returns the children position in the parent tree.
       *
       * @method ()
       * @public
       * @param {}          -,
       * @returns {Object}  returns the children position,
       * @since 0.0.8
       */

      var childIndex = function childIndex() {
        var child = this[0],
            index = 0;

        while (child !== null) {
          child = child.previousElementSibling;
          index += 1;
        }

        return index - 1;
      };
      /**
       * Returns the DOMRect object that bounds the contents of the range.
       *
       * @method ()
       * @public
       * @param {}          -,
       * @returns {Object}  returns the DOMRect object,
       * @since 0.0.8
       */

      var getRect = function getRect() {
        return this[0] ? this[0].getBoundingClientRect() : null;
      };
      /**
       * Gets/Sets the style attribute of the element,
       *
       * @method (arg1, arg2)
       * @public
       * @param {String}    the style attribute,
       * @param {String}    the style attribute value,
       * @returns {String}  returns the style attribute value or this,
       * @since 0.0.3
       */

      var css = function css(styleAttr, value) {
        var arr = typeof styleAttr === 'string' ? styleAttr.split('-') : [];
        var attr = ''; // Convert style attribute name with '-' (ex.: 'font-size' to 'fontSize'):

        for (var i = 0; i < arr.length; i++) {
          if (i === 0) {
            attr += arr[i];
          } else {
            attr += arr[i].charAt(0).toUpperCase() + arr[i].slice(1);
          }
        }

        if (!value) {
          // Get attribute:
          return this[0].style[attr];
        } // Set attribute:

        this[0].style[attr] = value;
        return this;
      };
      /**
       * Returns the DOMTokenList collection of the class attributes of the element.
       *
       * @method ()
       * @public
       * @param {}          -,
       * @returns {Object}  returns the DOMTokenList of the element,
       * @since 0.0.0
       */

      var getClassList = function getClassList() {
        return this[0].classList;
      };
      /**
       * Adds a class name to the element.
       *
       * @method (arg1)
       * @public
       * @param {String}    the class name to add,
       * @returns {Object}  returns this,
       * @since 0.0.0
       */

      var addClass = function addClass(className) {
        this[0].classList.add(className);
        return this;
      };
      /**
       * Adds a list of classes to the element.
       *
       * @method (arg1)
       * @public
       * @param {Array}     the list of classes to add,
       * @returns {Object}  returns this,
       * @since 0.0.8
       */

      var addClasses = function addClasses(classes) {
        if (Array.isArray(classes)) {
          for (var i = 0; i < classes.length; i++) {
            this[0].classList.add(classes[i]);
          }
        }

        return this;
      };
      /**
       * Removes a class name from the element.
       *
       * @method (arg1)
       * @public
       * @param {String}    the class name to remove,
       * @returns {Object}  returns this,
       * @since 0.0.0
       */

      var removeClass = function removeClass(className) {
        this[0].classList.remove(className);
        return this;
      };
      /**
       * Removes a list of classes from the element.
       *
       * @method (arg1)
       * @public
       * @param {Array}     the list of classes to remove,
       * @returns {Object}  returns this,
       * @since 0.0.8
       */

      var removeClasses = function removeClasses(classes) {
        if (Array.isArray(classes)) {
          for (var i = 0; i < classes.length; i++) {
            this[0].classList.remove(classes[i]);
          }
        }

        return this;
      };
      /**
       * Toggles a class name for the element.
       *
       * @method (arg1)
       * @public
       * @param {String}    the class name to add/remove,
       * @returns {Object}  returns this,
       * @since 0.0.0
       */

      var toggleClass = function toggleClass(className) {
        this[0].classList.toggle(className);
        return this;
      };
      /**
       * Checks if the element has the passed-in class.
       *
       * @method (arg1)
       * @public
       * @param {String}    the class name,
       * @returns {Boolean} returns true or false,
       * @since 0.0.8
       */

      var hasClass = function hasClass(className) {
        var list = this[0].classList.value.split(' ');

        if (Object.prototype.toString.call(className) === '[object String]' && list.indexOf(className) !== -1) {
          return true;
        }

        return false;
      };
      /**
       * Sets or Gets the specified attribute.
       *
       * @method (arg1, arg2)
       * @public
       * @param {String}    the attribute name,
       * @param {String}    the attribute value,
       * @returns {String}  returns the attribute value or this,
       * @since 0.0.6
       */

      var attr = function attr(attribute, value) {
        if (value) {
          this[0].setAttribute(attribute, value);
          return this;
        }

        return this[0].getAttribute(attribute);
      };
      /**
       * Removes the specified attribute.
       *
       * @method (arg1)
       * @public
       * @param {String}    the attribute name,
       * @returns {Object}  returns this,
       * @since 0.0.0
       */

      var removeAttr = function removeAttr(attribute) {
        if (attribute) {
          this[0].removeAttribute(attribute);
        }

        return this;
      };
      /**
       * Performs a custom animation of a set of CSS properties.
       *
       * @method (properties [, duration ] [, easing ] [, complete ])
       * @public
       * @param {Object}    An object of CSS properties,
       * @param {Number}    define how long the animation run,
       * @param {Easing}    the easing animation method,
       * @param {Function}  the function to call at completion,
       * @returns {Object}  returns this,
       * @since 0.0.7
       */

      var animate = function animate(properties) {
        var DTIME = 400,
            FAST = 200,
            SLOW = 600,
            INC = 10,
            elem = this[0],
            delay = INC; // Is the argument properties an object?

        if (!_overslash.default.isLiteralObject(properties)) {
          return this;
        } // Extract the optional arguments:

        for (var _len = arguments.length, args = new Array(_len > 1 ? _len - 1 : 0), _key = 1; _key < _len; _key++) {
          args[_key - 1] = arguments[_key];
        }

        var argus = _animate.default.extractArgs(args); // Set the duration:

        var duration = _overslash.default.isNumber(argus.duration) ? argus.duration : function (arg) {
          if (arg === 'fast') return FAST;
          if (arg === 'slow') return SLOW;
          return DTIME;
        }(argus.duration); // Set the easing (swing only for the time being):

        var easing = _animate.default.easing && _animate.default.easing[argus.easing] ? _animate.default.easing[argus.easing] : _animate.default.swing; // Set the callback:

        var callback = argus.callback ? argus.callback : null; // Run the animation:

        _animate.default.run(elem, properties, easing, duration, delay, callback); // Test Mode:

        if (_vizu.default.vdom) {
          this.probe = {
            duration: duration,
            easing: _animate.default.easing && _animate.default.easing[argus.easing] ? argus.easing : 'swing',
            callback: callback
          };
        }

        return this;
      };
      /**
       * Attachs an event listener to the current node.
       *
       * @method (arg1, arg2)
       * @public
       * @param {String}    the DOM event string,
       * @param {Function}  the listner function,
       * @returns {Object}  returns this,
       * @since 0.0.5
       */

      var on = function on(event, listener) {
        this[0].addEventListener(event, listener);
        return this;
      };
      /**
       * Removes an event listener from the current node.
       *
       * @method (arg1, arg2)
       * @public
       * @param {String}    the DOM event string,
       * @param {Function}  the listner function,
       * @returns {Object}  returns this,
       * @since 0.0.5
       */

      var off = function off(event, listener) {
        this[0].removeEventListener(event, listener);
        return this;
      }; // -- Main

      if (selector) {
        // Selects the first element that matches the selector(s):
        el = docu.querySelector("#".concat(cid)).querySelector(selector);
      } else {
        // Selects the entire 'web component':
        el = docu.querySelector("#".concat(cid));
      }

      return {
        0: el,
        id: el ? el.id : null,
        select: select,
        selectChild: selectChild,
        parent: parent,
        firstParent: firstParent,
        html: html,
        empty: empty,
        append: append,
        prepend: prepend,
        after: after,
        before: before,
        replaceWith: replaceWith,
        text: text,
        clone: clone,
        insertChildBefore: insertChildBefore,
        removeChild: removeChild,
        replaceChild: replaceChild,
        children: children,
        childIndex: childIndex,
        getRect: getRect,
        css: css,
        getClassList: getClassList,
        addClass: addClass,
        addClasses: addClasses,
        removeClass: removeClass,
        removeClasses: removeClasses,
        toggleClass: toggleClass,
        hasClass: hasClass,
        attr: attr,
        removeAttr: removeAttr,
        animate: animate,
        on: on,
        off: off
      };
    }
    /**
     * Attaches event(s) to the given node.
     *
     * @method (arg1, arg2)
     * @public
     * @param {String}    the DOM event name,
     * @param {Function}  the event listener,
     * @returns {Funtion} returns this,
     * @since 0.0.5
     */

    /* istanbul ignore next */

  }, {
    key: "events",
    value: function events() {
      // Just to avoid eslint error!
      return this;
    }
    /**
     * Returns the defined web component.
     *
     * @method ()
     * @public
     * @param {}          -,
     * @returns {String}  returns the web component,
     * @since 0.0.0
     */

  }, {
    key: "render",
    value: function render() {
      /* istanbul ignore next */
      return "<div>".concat(this.id, "</div>");
    }
    /**
     * Processes the web component to convert child(s) to plain HTML.
     *
     * @method ()
     * @private
     * @param {}          -,
     * @returns {String}  returns the web component,
     * @since 0.0.0
     */

  }, {
    key: "rendered",
    get: function get() {
      var t; // Initializes:

      this.getInitialState(); // Add an unique ID to this component:
      // let t = this.render().replace(/<div>/, `<div id="${this.id}">`);

      var co = this.render();

      if (co.match(/^\s*<div/)) {
        t = co.replace(/^\s*<div/, "<div id= \"".concat(this.id, "\""));
      } else if (co.match(/^\s*<header/)) {
        t = co.replace(/^\s*<header/, "<header id= \"".concat(this.id, "\""));
      } else if (co.match(/^\s*<footer/)) {
        t = co.replace(/^\s*<footer/, "<footer id= \"".concat(this.id, "\""));
      } else {
        t = co;
      }

      if (this.cList) {
        // This component includes components, render them:
        this.components = {};
        var keys = Object.keys(this.cList);

        for (var i = 0; i < keys.length; i++) {
          var c = new this.cList[keys[i]]();
          t = t.replace(keys[i], c.rendered);
          this.components[keys[i].replace(/[^a-zA-z0-9]/g, '')] = c;
        }
      } // Return the rendered web component:

      return t;
    }
    /**
     * Processes the web component events.
     *
     * @method ()
     * @private
     * @param {}          -,
     * @returns {}        -,
     * @since 0.0.5
     */

  }, {
    key: "evented",
    get: function get() {
      return this.events();
    }
  }]);

  return Component;
}();

var _default = Component;
exports.default = _default;
module.exports = exports.default;

},{"./private/animate":3,"./private/overslash":4,"./vizu":6}],3:[function(require,module,exports){
"use strict";

Object.defineProperty(exports, "__esModule", {
  value: true
});
exports.default = void 0;

var _overslash = _interopRequireDefault(require("./overslash"));

var _utilities = _interopRequireDefault(require("./utilities"));

function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }

/* global */

/* eslint one-var: 0, semi-style: 0, prefer-destructuring: 0 */
// -- Vendor modules
// -- Local modules
// -- Global constants (in the scope of this module)
// -- Public Methods -----------------------------------------------------------
var _default = {
  /**
   * Extracts the optional argument of 'animate'.
   *
   * @function (arg1, arg2, arg3)
   * @private
   * @param {?}         duration, easing or callback,
   * @param {?}         easing or callback,
   * @param {Object}    the function to call at completion,
   * @returns {Object}  returns an object with the properties duration, easing
   *                    and callback,
   * @since 0.0.7
   */
  extractArgs: function extractArgs() {
    for (var _len = arguments.length, arg = new Array(_len), _key = 0; _key < _len; _key++) {
      arg[_key] = arguments[_key];
    }

    var nb = arg[0].length,
        args = arg[0];
    var duration, easing, callback;

    switch (nb) {
      case 0:
        break;

      case 1:
        if (_overslash.default.isNumber(args[0]) || args[0] === 'fast' || args[0] === 'slow') {
          duration = args[0];
        } else if (_overslash.default.isString(args[0])) {
          easing = args[0];
        } else if (_overslash.default.isFunction(args[0])) {
          callback = args[0];
        }

        break;

      case 2:
        if (_overslash.default.isNumber(args[0]) || args[0] === 'fast' || args[0] === 'slow') {
          duration = args[0];

          if (_overslash.default.isString(args[1])) {
            easing = args[1];
          } else if (_overslash.default.isFunction(args[1])) {
            callback = args[1];
          }
        } else if (_overslash.default.isString(args[0])) {
          easing = args[0];

          if (_overslash.default.isFunction(args[1])) {
            callback = args[1];
          }
        }

        break;

      case 3:
        if (_overslash.default.isNumber(args[0]) || args[0] === 'fast' || args[0] === 'slow') {
          duration = args[0];
        }

        if (_overslash.default.isString(args[1])) {
          easing = args[1];
        }

        if (_overslash.default.isFunction(args[2])) {
          callback = args[2];
        }

        break;

      /* istanbul ignore next */

      default:
        break;
    }

    return {
      duration: duration,
      easing: easing,
      callback: callback
    };
  },

  /**
   * Retrieves the CSS property values for the given node.
   *
   * @function (arg1, arg2)
   * @private
   * @param {Object}    the given node,
   * @param {Object}    the CSS properties to animate,
   * @returns {Object}  returns an object with the properties initial, change, suffix
   *                    per animated property,
   * @since 0.0.7
   */
  getProps: function getProps(el, properties) {
    var keys = Object.keys(properties),
        props = {},
        names = [];
    var name, i; // Parse the properties:

    for (i = 0; i < keys.length; i++) {
      // Normalize the name of the property:
      name = _utilities.default.normalizeCssPropertyName(keys[i]); // Check it is a valid CSS property:

      if (el.style[name]) {
        names.push(name);
        props[name] = {
          initial: parseFloat(el.style[name], 10),
          change: parseFloat(properties[keys[i]]) - parseFloat(el.style[name]),
          suffix: el.style[name].replace(/[0-9.]/g, '')
        };
      }
    }

    props.name = names;
    return props;
  },

  /**
   * Updates dynamically the CSS properties from their initial value to their final.
   *
   * @function (arg1, arg2, arg3, arg4, arg5, arg6)
   * @private
   * @param {Object}    the given node,
   * @param {Object}    the CSS properties to update,
   * @param {Function}  the easing method,
   * @param {Number}    the animation duration,
   * @param {Number}    the animation step,
   * @param {Function}  the function to call at the completion,
   * @returns {}        -,
   * @since 0.0.7
   */
  run: function run(el, properties, easing, duration, delay, callback) {
    var props = this.getProps(el, properties),
        elem = el;
    var lapseOfTime = 0;
    var timer = setInterval(function () {
      lapseOfTime += delay;

      if (lapseOfTime > duration) {
        clearInterval(timer);
        if (callback) callback();
      } // easing:

      for (var i = 0; i < props.name.length; i++) {
        elem.style[props.name[i]] = easing(lapseOfTime, props[props.name[i]].initial, props[props.name[i]].change, duration) + props[props.name[i]].suffix;
      }
    }, delay);
  },

  /**
   * The default easing method (if PicoQ.easing.e() aren't provided).
   *
   * @function (arg1, arg2, arg3, arg4)
   * @private
   * @param {Number}    the current lapse time,
   * @param {Number}    the initial CSS property value,
   * @param {Number}    the difference between the final and the initial value,
   * @param {Number}    the animation duration,
   * @returns {Number}  returns the value of the CSS property at the current lapse time,
   * @since 0.0.7
   */

  /* eslint-disable no-mixed-operators */
  swing: function swing(t, b, c, d) {
    return c * (0.5 - Math.cos(t / d * Math.PI) / 2) + b;
  }
};
/* eslint-enable no-underscore-dangle */

exports.default = _default;
module.exports = exports.default;

},{"./overslash":4,"./utilities":5}],4:[function(require,module,exports){
"use strict";

Object.defineProperty(exports, "__esModule", {
  value: true
});
exports.default = void 0;

/* global */

/* eslint one-var: 0 */
// -- Vendor modules
// -- Local modules
// -- Global constants (in the scope of this module)
// -- Public Methods -----------------------------------------------------------
var _default = {
  /**
   * Is a given value a string?
   *
   * @function (arg1)
   * @private
   * @param {Object}      the object to test,
   * @returns {Boolean}   returns true or false,
   * @since 0.0.7
   */
  isString: function isString(obj) {
    return Object.prototype.toString.call(obj) === '[object String]';
  },

  /**
   * Is a given value a number?
   *
   * @function (arg1)
   * @private
   * @param {Object}      the object to test,
   * @returns {Boolean}   returns true or false,
   * @since 0.0.7
   */
  isNumber: function isNumber(obj) {
    return Object.prototype.toString.call(obj) === '[object Number]';
  },

  /**
   * Is a given variable a literal object?
   *
   * @function (arg1)
   * @private
   * @param {Object}    the object to test,
   * @returns {Boolean} returns true or false,
   * @since 0.0.7
   */
  isLiteralObject: function isLiteralObject(obj) {
    return Object.prototype.toString.call(obj) === '[object Object]';
  },

  /**
   * Is a given variable a function?
   *
   * @function (arg1)
   * @private
   * @param {Object}    the object to test,
   * @returns {Boolean} returns true or false,
   * @since 0.0.7
   */
  isFunction: function isFunction(obj) {
    return Object.prototype.toString.call(obj) === '[object Function]';
  }
};
exports.default = _default;
module.exports = exports.default;

},{}],5:[function(require,module,exports){
"use strict";

Object.defineProperty(exports, "__esModule", {
  value: true
});
exports.default = void 0;

var _overslash = _interopRequireDefault(require("./overslash"));

function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }

/* global */

/* eslint one-var: 0, semi-style: 0 */
// -- Vendor modules
// -- Local modules
// -- Global constants (in the scope of this module)
// -- Public Methods -----------------------------------------------------------
var _default = {
  /**
   * Normalizes the CSS properties.
   * (replace '-' between composite name by camelcase style).
   * Ex: font-size -> fontSize
   *
   * @function (arg1)
   * @private
   * @param {String}    the CSS property name,
   * @returns {String}  the normalized CSS property name,
   * @since 0.0.7
   */
  normalizeCssPropertyName: function normalizeCssPropertyName(name) {
    var arr = _overslash.default.isString(name) ? name.split('-') : [];
    var normalized = ''; // Convert name with '-' (ex.: 'font-size' to 'fontSize'):

    for (var i = 0; i < arr.length; i++) {
      if (i === 0) {
        normalized += arr[i];
      } else {
        normalized += arr[i].charAt(0).toUpperCase() + arr[i].slice(1);
      }
    }

    return normalized;
  }
};
exports.default = _default;
module.exports = exports.default;

},{"./overslash":4}],6:[function(require,module,exports){
"use strict";

Object.defineProperty(exports, "__esModule", {
  value: true
});
exports.default = void 0;

var _component = _interopRequireDefault(require("./component"));

function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }

function _typeof(obj) { if (typeof Symbol === "function" && typeof Symbol.iterator === "symbol") { _typeof = function _typeof(obj) { return typeof obj; }; } else { _typeof = function _typeof(obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; }; } return _typeof(obj); }

// -- Global constants (in the scope of this module)
// -- Private Functions --------------------------------------------------------

/**
 * Returns the path of the matching Web Component.
 *
 * @function ()
 * @private
 * @param {Object}    the view object,
 * @param {String}    the tag defining a Web Component
 * @returns {Object}  the path of the matching Web Component,
 */
var explore = function explore(view, tag) {
  if (view.cList && view.cList[tag]) {
    return view;
  }

  var keys = Object.keys(view);

  for (var i = 0; i < keys.length; i++) {
    if (view[keys[i]].cList) {
      if (view[keys[i]].cList[tag]) {
        return view[keys[i]];
      }

      if (view[keys[i]].components) {
        return explore(view[keys[i]].components, tag);
      }
    }
  }

  return null;
};
/**
 * Attaches events to the rendered components.
 *
 * @function (arg1)
 * @private
 * @param {Object}    the view object,
 * @returns {}        -,
 */

var attachEvents = function attachEvents(view) {
  /* eslint-disable no-unused-expressions */
  if (view.cList) {
    var keys = Object.keys(view.cList);
    var fn;

    for (var i = 0; i < keys.length; i++) {
      if (!view.components) {
        // Extract components at the first level:
        fn = view[keys[i].replace(/[^a-zA-z0-9]/g, '')];
      } else {
        // Extract components at levels n + 1:
        fn = view.components[keys[i].replace(/[^a-zA-z0-9]/g, '')];
      } // Run Component events function:

      fn.evented; // Process sub components recursively:

      attachEvents(fn);
    }
  }
};
/* eslint-enable no-unused-expressions */

/**
 * Code reused from Babel
 */

var _createClass = function () {
  function defineProperties(target, props) {
    for (var i = 0; i < props.length; i++) {
      var descriptor = props[i];
      descriptor.enumerable = descriptor.enumerable || false;
      descriptor.configurable = true;

      if ('value' in descriptor) {
        descriptor.writable = true;
      }

      Object.defineProperty(target, descriptor.key, descriptor);
    }
  }

  return function (Constructor, protoProps, staticProps) {
    if (protoProps) {
      defineProperties(Constructor.prototype, protoProps);
    }

    if (staticProps) {
      /* istanbul ignore next */
      defineProperties(Constructor, staticProps);
    }

    return Constructor;
  };
}();
/**
 * Code reused from Babel
 */

var _possibleConstructorReturn = function _possibleConstructorReturn(self, call) {
  if (!self) {
    /* istanbul ignore next */
    throw new ReferenceError("this hasn't been initialised - super() hasn't been called");
  }

  return call && (_typeof(call) === 'object' || typeof call === 'function') ? call : self;
};
/**
 * Code reused from Babel
 */

var _inherits = function _inherits(subClass, superClass) {
  if (typeof superClass !== 'function' && superClass !== null) {
    /* istanbul ignore next */
    throw new TypeError("Super expression must either be null or a function, not ".concat(_typeof(superClass)));
  }

  subClass.prototype = Object.create(superClass && superClass.prototype, {
    constructor: {
      value: subClass,
      enumerable: false,
      writable: true,
      configurable: true
    }
  });

  if (superClass) {
    Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass;
  }
};
/**
 * Code reused from Babel
 */

var _classCallCheck = function _classCallCheck(instance, Constructor) {
  if (!(instance instanceof Constructor)) {
    /* istanbul ignore next */
    throw new TypeError('Cannot call a class as a function');
  }
};
/**
 * Code reused from Babel
 */

var _subClass = function _subClass(SuperClass, m) {
  function SubClass() {
    _classCallCheck(this, SubClass);

    return _possibleConstructorReturn(this, (SubClass.__proto__ || Object.getPrototypeOf(SubClass)).apply(this, arguments));
  }

  _inherits(SubClass, SuperClass);

  _createClass(SubClass, m);

  return SubClass;
}; // -- Public Methods -----------------------------------------------------------

/**
* This library renders the View in the DOM.
*
* @namespace Vizu
*/

var Vizu = {
  /**
   * Returns the version of this library.
   *
   * @method ()
   * @public
   * @param {}          -,
   * @returns {String}  returns the version of this library,
   */
  version: function version() {
    return '0.0.10';
  },

  /**
   * Renders the View in the DOM.
   *
   * @method (arg1, arg2, arg3)
   * @public
   * @param {String}    the aggregated web components,
   * @param {Object}    the list of web components and their reference,
   * @param {Object}    the DOM element where the view (the aggregate of web components) is inserted,
   * @returns {Object}  returns the view object,
   * @since 0.0.0
   */
  render: function render(template, cList, el) {
    var keys = Object.prototype.toString.call(cList) === '[object Object]' ? Object.keys(cList) : [],
        view = {};
    var t; // Return null if the template is not a string:

    if (typeof template !== 'string') {
      return null;
    } // If no components, render the template as is:

    if (!cList) {
      if (el) {
        el.innerHTML = template;
      } else {
        Vizu.vdom ? Vizu.vdom.window.document.body.innerHTML += template : document.body.innerHTML += template;
      }

      return null;
    } // This view includes components, render them:

    t = template;

    for (var i = 0; i < keys.length; i++) {
      var c = new cList[keys[i]]();
      t = t.replace(keys[i], c.rendered);
      view[keys[i].replace(/[^a-zA-z0-9]/g, '')] = c;
    } // Attach cList:

    view.cList = keys.length > 0 ? cList : null; // Fill the DOM:

    if (el) {
      el.innerHTML = t;
    } else {
      el = Vizu.vdom ? Vizu.vdom.window.document.body : document.body; // Attach the component to the body as the first child:

      el.innerHTML = t + el.innerHTML;
    } // Attach event(s)
    // parse all components and for each component execute evented!

    attachEvents(view); // Attach parent element:

    view.el = el; // Return the rendered object (with a reference to all the web components):

    return view;
  },

  /**
   * Replaces a component with another component having the same tag.
   *
   * @method (arg1, arg2)
   * @public
   * @param {Object}    the view object,
   * @param {Object}    the new component ({ '<Aaa />': 'new class' }),
   * @returns {}        -,
   * @since 0.0.0
   */
  replace: function replace(view, component) {
    var id, type; // Check that view is an object with, at least, the properties cList and el:

    if (Object.prototype.toString.call(view) !== '[object Object]' || !view.cList || !view.el) {
      return;
    } // Check that component is an object:

    if (Object.prototype.toString.call(component) !== '[object Object]') {
      return;
    } // Process the new component:

    var newctag = Object.keys(component)[0];
    var newcname = newctag.replace(/[^a-zA-z0-9]/g, '');
    var newc = new component[newctag](); // Check if a component with the same name already exists in the view:

    var path = explore(view, newctag);

    if (path) {
      // Get its id and remove it:
      if (path[newcname]) {
        id = path[newcname].id;
        path[newcname] = null;
        type = 1;
      } else {
        id = path.components[newcname].id;
        path.components[newcname] = null;
        type = 2;
      }

      path.cList[newctag] = null; // Get its id and clear it:

      var wrapper = Vizu.vdom ? Vizu.vdom.window.document.createElement('div') : document.createElement('div');
      var oldNode = Vizu.vdom ? Vizu.vdom.window.document.getElementById(id) : document.getElementById(id);
      wrapper.innerHTML = newc.rendered;
      oldNode.parentNode.replaceChild(wrapper.firstChild, oldNode); // Attach the new node to view:

      if (type === 1) {
        path[newcname] = newc;
      } else {
        path.components[newcname] = newc;
      }

      path.cList[newctag] = component[newctag];
    }
  },

  /**
   * Extends the class Component.
   *
   * @method (arg1)
   * @public
   * @param {Object}    the methods to add to Component,
   * @returns {Object}  returns the extended class component,
   * @since 0.0.3
   */
  createClass: function createClass(methods) {
    // Check that methods is an object:
    if (Object.prototype.toString.call(methods) !== '[object Object]') {
      return null;
    } // Extract keys:

    var keys = Object.keys(methods);
    var o = [];

    for (var i = 0; i < keys.length; i++) {
      o.push({
        key: keys[i],
        value: methods[keys[i]]
      });
    }

    return _subClass(_component.default, o);
  }
};
var _default = Vizu;
exports.default = _default;
module.exports = exports.default;

},{"./component":2}]},{},[1])(1)
});

//# sourceMappingURL=vizu.js.map