text:
extern bool sdCardFileSystemReady;
#endif
#if (HAL_USBH_USE_MSD == TRUE)
extern bool usbMsdFileSystemReady;
#endif
#if (NF_FEATURE_USE_SPIFFS == TRUE)
extern bool spiffsFileSystemReady;
#endif

void CombinePath(char *outpath, const char *path1, const char *path2)
{
    strcat(outpath, path1);

    // Add "\" to path if required
    if (outpath[hal_strlen_s(outpath) - 1] != '\\')
    {
        strcat(outpath, "\\");
    }
    strcat(outpath, path2);
}

SYSTEMTIME GetDateTime(uint16_t date, uint16_t time)
{
    SYSTEMTIME fileTime;

    memset(&fileTime, 0, sizeof(SYSTEMTIME));

    // date (bit15:9) Year origin from 1980 (0..127)
    fileTime.wYear = (date >> 9) + 1980;
    // date (bit8:5) Month (1..12)
    fileTime.wMonth = (date >> 5) & 0x000F;
    // date (bit4:0) Day (1..31)
    fileTime.wDay = date & 0x001F;

    // time (bit15:11) Hour (0..23)
    fileTime.wHour = (time >> 11) & 0x001F;
    // time (bit10:5) Minute (0..59)
    fileTime.wMinute = (time >> 5) & 0x003F;
    // time (bit4:0) Second / 2 (0..29)
    fileTime.wSecond = time & 0x001F;

    return fileTime;
}

// Save a DateTime (ticks) to DateTime field in object
void SaveDateTimeToField(CLR_RT_HeapBlock *hbObj, int fieldIndex, CLR_UINT64 ticks)
{
    CLR_RT_HeapBlock &dateFieldRef = hbObj[fieldIndex];
    CLR_INT64 *pRes = Library_corlib_native_System_DateTime::GetValuePtr(dateFieldRef);
    if (pRes)
    {
        // ...and set it
        *pRes = ticks;
    }
}

HRESULT Library_win_storage_native_Windows_Storage_StorageFolder::
    GetRemovableStorageFoldersNative___SZARRAY_WindowsStorageStorageFolder(CLR_RT_StackFrame &stack)
{
    NANOCLR_HEADER();

    char *stringBuffer;
    uint32_t driveCount = 0;
    char workingDrive[sizeof(DRIVE_PATH_LENGTH)];
    uint16_t maxDriveCount = 0;

    CLR_RT_HeapBlock *storageFolder;
    CLR_RT_TypeDef_Index storageFolderTypeDef;
    CLR_RT_HeapBlock *hbObj;
    CLR_RT_HeapBlock &top = stack.PushValue();

#if HAL_USE_SDC
    // increase max drive count
    maxDriveCount++;

    // is the SD card file system ready?
    if (sdCardFileSystemReady)
    {
        // add count
        driveCount++;
    }
#endif

#if HAL_USBH_USE_MSD
    // increase max drive count
    maxDriveCount++;

    // is the USB mass storage device file system ready?
    if (usbMsdFileSystemReady)
    {
        // add count
        driveCount++;
    }
#endif

    // start composing the reply
    // find <StorageFolder> type definition, don't bother checking the result as it exists for sure
    g_CLR_RT_TypeSystem.FindTypeDef("StorageFolder", "Windows.Storage", storageFolderTypeDef);

    // create an array of <StorageFolder>
    NANOCLR_CHECK_HRESULT(CLR_RT_HeapBlock_Array::CreateInstance(top, driveCount, storageFolderTypeDef));

#if (HAL_USE_SDC == TRUE) || (HAL_USBH_USE_MSD == TRUE)

    if (driveCount > 0)
    {
        // there are driver present and enumerated

        // get a pointer to the first object in the array (which is of type <StorageFolder>)
        storageFolder = (CLR_RT_HeapBlock *)top.DereferenceArray()->GetFirstElement();

        // loop until we've loaded all the possible drives
        // because we are iterating through an enum, need to use its integer values
        for (uint16_t driveIterator = 0; driveIterator < maxDriveCount; driveIterator++)
        {
            // fill the folder name and path

#if HAL_USE_SDC
            // SD card has index 0
            if (driveIterator == SD_CARD_DRIVE_INDEX_NUMERIC)
            {
                // is the SD card file system ready?
                if (sdCardFileSystemReady)
                {
                    memcpy(workingDrive, INDEX0_DRIVE_PATH, DRIVE_PATH_LENGTH);
                }
                else
                {
                    // SD card file system is not ready and/or no drive is enumerated
                    continue;
                }
            }
#endif

#if HAL_USBH_USE_MSD
            // USB MSD has index 0 or 1, depending on the us of SD card
            if (driveIterator == USB_MSD_DRIVE_INDEX_NUMERIC)
            {
                // is the USB mass storage device file system ready?
                if (usbMsdFileSystemReady)
                {
                    memcpy(workingDrive, INDEX1_DRIVE_PATH, DRIVE_PATH_LENGTH);
                }
                else
                {
                    // USB mass storage file system is not ready and/or no drive is enumerated
                    continue;
                }
            }
#endif

            // create an instance of <StorageFolder>
            NANOCLR_CHECK_HRESULT(g_CLR_RT_ExecutionEngine.NewObjectFromIndex(*storageFolder, storageFolderTypeDef));

            // dereference the object in order to reach its fields
            hbObj = storageFolder->Dereference();

            // set the managed fields
            NANOCLR_CHECK_HRESULT(CLR_RT_HeapBlock_String::CreateInstance(
                hbObj[Library_win_storage_native_Windows_Storage_StorageFolder::FIELD___name],
                workingDrive));
            NANOCLR_CHECK_HRESULT(CLR_RT_HeapBlock_String::CreateInstance(
                hbObj[Library_win_storage_native_Windows_Storage_StorageFolder::FIELD___path],
                workingDrive));

            // malloc stringBuffer to work with FS
            stringBuffer = (char *)platform_malloc(FF_LFN_BUF + 1);

            // sanity check for successful malloc
            if (stringBuffer == NULL)
            {
                // failed to allocate memory
                NANOCLR_SET_AND_LEAVE(CLR_E_OUT_OF_MEMORY);
            }
            else
            {
                // clear buffer
                memset(stringBuffer, 0, FF_LFN_BUF + 1);

                // read the drive volume label
                // don't bother checking the result, if anything goes wrong we'll end up with an empty string which is
                // OK
                f_getlabel(workingDrive, stringBuffer, NULL);

                // add the driver letter separated it with an empty space, if the volume label isn't empty
                if (*stringBuffer != '\0')
                {
                    strcat(stringBuffer, " ");
                }
                strcat(stringBuffer, "(");
                strcat(stringBuffer, workingDrive);
                strcat(stringBuffer, ")");

                // set the field with the volume label
                NANOCLR_CHECK_HRESULT(CLR_RT_HeapBlock_String::CreateInstance(
                    hbObj[Library_win_storage_native_Windows_Storage_StorageFolder::FIELD___name],
                    stringBuffer));

                // free stringBuffer
                platform_free(stringBuffer);
            }

            // move pointer to the next folder item
            storageFolder++;
        }
    }

#endif

    NANOCLR_NOCLEANUP();
}

HRESULT Library_win_storage_native_Windows_Storage_StorageFolder::
    GetInternalStorageFoldersNative___SZARRAY_WindowsStorageStorageFolder(CLR_RT_StackFrame &stack)
{
    NANOCLR_HEADER();

    uint32_t driveCount = 0;
    char workingDrive[sizeof(DRIVE_PATH_LENGTH)];

    CLR_RT_HeapBlock *storageFolder;
    CLR_RT_TypeDef_Index storageFolderTypeDef;
    CLR_RT_HeapBlock *hbObj;
    CLR_RT_HeapBlock &top = stack.PushValue();

#if (NF_FEATURE_USE_SPIFFS == TRUE)
    // is the SPIFFS file system available and mounted?
    if (spiffsFileSystemReady)
    {
        // get SPIFFS instances count
        driveCount = hal_spiffs_get_instances_count();
    }
#endif

    // start composing the reply
    // find <StorageFolder> type definition, don't bother checking the result as it exists for sure
    g_CLR_RT_TypeSystem.FindTypeDef("StorageFolder", "Windows.Storage", storageFolderTypeDef);

    // create an array of <StorageFolder>
    NANOCLR_CHECK_HRESULT(CLR_RT_HeapBlock_Array::CreateInstance(top, driveCount, storageFolderTypeDef));

    // get a pointer to the first object in the array (which is of type <StorageFolder>)
    storageFolder = (CLR_RT_HeapBlock *)top.DereferenceArray()->GetFirstElement();

    for (uint16_t driveIterator = 0; driveIterator < driveCount; driveIterator++)
    {
        // SPIFFS is mounted

        // create an instance of <StorageFolder>
        NANOCLR_CHECK_HRESULT(g_CLR_RT_ExecutionEngine.NewObjectFromIndex(*storageFolder, storageFolderTypeDef));

        // fill the folder name and path
        switch (driveIterator)
        {
            case 0:
                memcpy(workingDrive, INTERNAL_DRIVE0_PATH, DRIVE_PATH_LENGTH);
                break;

            case 1:
                memcpy(workingDrive, INTERNAL_DRIVE1_PATH, DRIVE_PATH_LENGTH);
                break;

            default:
                HAL_AssertEx();
                NANOCLR_SET_AND_LEAVE(CLR_E_FAIL);
        }

        // dereference the object in order to reach its fields
        hbObj = storageFolder->Dereference();

        // set the managed fields
        NANOCLR_CHECK_HRESULT(CLR_RT_HeapBlock_String::CreateInstance(
            hbObj[Library_win_storage_native_Windows_Storage_StorageFolder::FIELD___name],
            workingDrive));
        NANOCLR_CHECK_HRESULT(CLR_RT_HeapBlock_String::CreateInstance(
            hbObj[Library_win_storage_native_Windows_Storage_StorageFolder::FIELD___path],
            workingDrive));

        // move pointer to the next folder item
        storageFolder++;
    }

    NANOCLR_NOCLEANUP();
}

HRESULT Library_win_storage_native_Windows_Storage_StorageFolder::
    GetStorageFoldersNative___SZARRAY_WindowsStorageStorageFolder(CLR_RT_StackFrame &stack)
{
    NANOCLR_HEADER();

    CLR_RT_TypeDef_Index storageFolderTypeDef;
    CLR_RT_HeapBlock *storageFolder;
    CLR_RT_HeapBlock *hbObj;
    SYSTEMTIME fileInfoTime;

#if ((HAL_USE_SDC == TRUE) || (HAL_USBH_USE_MSD == TRUE))

    const char *workingPath;
    char workingDrive[DRIVE_LETTER_LENGTH];

    DIR currentDirectory = {};
    FRESULT operationResult;
    static FILINFO fileInfo;
    uint16_t directoryCount = 0;
    char *stringBuffer = NULL;
    char *workingBuffer = NULL;

    CLR_RT_HeapBlock &top = stack.PushValue();

    // get a pointer to the managed object instance and check that it's not NULL
    CLR_RT_HeapBlock *pThis = stack.This();
    FAULT_ON_NULL(pThis);

    // copy the first 2 letters of the path for the drive
    // path is 'D:\folder\file.txt', so we need 'D:'
    memcpy(
        workingDrive,
        pThis[Library_win_storage_native_Windows_Storage_StorageFolder::FIELD___path].DereferenceString()->StringText(),
        DRIVE_LETTER_LENGTH);

    // get a pointer to the path in managed field
    workingPath =
        pThis[Library_win_storage_native_Windows_Storage_StorageFolder::FIELD___path].DereferenceString()->StringText();

    // open directory
    operationResult = f_opendir(&currentDirectory, workingPath);

    if (operationResult != FR_OK)
    {
        if (operationResult == FR_INVALID_DRIVE)
        {
            // failed to change drive

            // check if the working drive is the SPIFFS drive
#if (NF_FEATURE_USE_SPIFFS == TRUE)
            if (WORKING_DRIVE_IS_INTERNAL_DRIVE)
            {
                // this is the SPIFFS drive,
                // do nothing here and return an empty collection because folders aren't supported in SPIFFS
            }
            else
            {
#else
            {
#endif
                // invalid drive
                NANOCLR_SET_AND_LEAVE(CLR_E_VOLUME_NOT_FOUND);
            }
        }

        // error or directory empty
        // find <StorageFolder> type, don't bother checking the result as it exists for sure
        g_CLR_RT_TypeSystem.FindTypeDef("StorageFolder", "Windows.Storage", storageFolderTypeDef);

        // create an array of <StorageFolder>
        NANOCLR_CHECK_HRESULT(CLR_RT_HeapBlock_Array::CreateInstance(top, directoryCount, storageFolderTypeDef));
    }
    else
    {
        // need to perform this in two steps
        // 1st: count the directory objects
        // 2nd: create the array items with each directory object

        // perform 1st pass
        for (;;)
        {
            // read next directory item
            operationResult = f_readdir(&currentDirectory, &fileInfo);

            // break on error or at end of dir
            if (operationResult != FR_OK || fileInfo.fname[0] == 0)
            {
                break;
            }

            // check if this is a directory
            // but skip if:
            // - has system attribute set
            // - has hidden attribute set
            if ((fileInfo.fattrib & AM_DIR) && !(fileInfo.fattrib & AM_SYS) && !(fileInfo.fattrib & AM_HID))
            {
                directoryCount++;
            }
        }

        // find <StorageFolder> type, don't bother checking the result as it exists for sure
        g_CLR_RT_TypeSystem.FindTypeDef("StorageFolder", "Windows.Storage", storageFolderTypeDef);

        // create an array of <StorageFolder>
        NANOCLR_CHECK_HRESULT(CLR_RT_HeapBlock_Array::CreateInstance(top, directoryCount, storageFolderTypeDef));

        // get a pointer to the first object in the array (which is of type <StorageFolder>)
        storageFolder = (CLR_RT_HeapBlock *)top.DereferenceArray()->GetFirstElement();

        if (directoryCount > 0)
        {
            // allocate memory for buffers
            stringBuffer = (char *)platform_malloc(FF_LFN_BUF + 1);
            workingBuffer = (char *)platform_malloc(2 * FF_LFN_BUF + 1);

            // sanity check for successful malloc
            if (stringBuffer == NULL || workingBuffer == NULL)
            {
                // failed to allocate memory
                NANOCLR_SET_AND_LEAVE(CLR_E_OUT_OF_MEMORY);
            }

            // perform 2nd pass
            // need to rewind the directory read index first
            f_readdir(&currentDirectory, NULL);

            for (;;)
            {
                // read next directory item
                operationResult = f_readdir(&currentDirectory, &fileInfo);

                // break on error or at end of dir
                if (operationResult != FR_OK || fileInfo.fname[0] == 0)
                {
                    break;
                }

                // check if this is a directory
                // but skip if:
                // - has system attribute set
                // - has hidden attribute set
                if ((fileInfo.fattrib & AM_DIR) && !(fileInfo.fattrib & AM_SYS) && !(fileInfo.fattrib & AM_HID))
                {
                    // create an instance of <StorageFolder>
                    NANOCLR_CHECK_HRESULT(
                        g_CLR_RT_ExecutionEngine.NewObjectFromIndex(*storageFolder, storageFolderTypeDef));

                    // dereference the object in order to reach its fields
                    hbObj = storageFolder->Dereference();

                    // directory name
                    NANOCLR_CHECK_HRESULT(CLR_RT_HeapBlock_String::CreateInstance(
                        hbObj[Library_win_storage_native_Windows_Storage_StorageFolder::FIELD___name],
                        fileInfo.fname));

                    // clear working buffer
                    memset(workingBuffer, 0, 2 * FF_LFN_BUF + 1);

                    // compose directory path
                    CombinePath(workingBuffer, workingPath, fileInfo.fname);

                    NANOCLR_CHECK_HRESULT(CLR_RT_HeapBlock_String::CreateInstance(
                        hbObj[Library_win_storage_native_Windows_Storage_StorageFolder::FIELD___path],
                        workingBuffer));

                    // compute directory date
                    fileInfoTime = GetDateTime(fileInfo.fdate, fileInfo.ftime);

                    // Save fileInfoTime to StorageFolder date created field...
                    SaveDateTimeToField(
                        hbObj,
                        Library_win_storage_native_Windows_Storage_StorageFolder::FIELD___dateCreated,
                        HAL_Time_ConvertFromSystemTime(&fileInfoTime));

                    // move the storage folder pointer to the next item in the array
                    storageFolder++;
                }
            }
        }
    }

#elif (NF_FEATURE_USE_SPIFFS == TRUE)

    // SPIFFS doesn't support folders so return an empty collection
    CLR_RT_HeapBlock &top = stack.PushValue();

    // get a pointer to the managed object instance and check that it's not NULL
    CLR_RT_HeapBlock *pThis = stack.This();
    FAULT_ON_NULL(pThis);

    // find <StorageFolder> type, don't bother checking the result as it exists for sure
    g_CLR_RT_TypeSystem.FindTypeDef("StorageFolder", "Windows.Storage", storageFolderTypeDef);

    // create an array of <StorageFolder>
    NANOCLR_CHECK_HRESULT(CLR_RT_HeapBlock_Array::CreateInstance(top, directoryCount, storageFolderTypeDef));

#endif

    NANOCLR_CLEANUP();

#if ((HAL_USE_SDC == TRUE) || (HAL_USBH_USE_MSD == TRUE))
    // close directory, if it was ever opened
    if (currentDirectory.dir)
    {
        f_closedir(&currentDirectory);
    }

    // free buffers memory, if allocated
    if (stringBuffer != NULL)
    {
        platform_free(stringBuffer);
    }
    if (workingBuffer != NULL)
    {
        platform_free(workingBuffer);
    }
#endif

    NANOCLR_CLEANUP_END();
}

HRESULT Library_win_storage_native_Windows_Storage_StorageFolder::
    GetStorageFilesNative___SZARRAY_WindowsStorageStorageFile__U4__U4(CLR_RT_StackFrame &stack)
{
    NANOCLR_HEADER();

    CLR_RT_TypeDef_Index storageFileTypeDef;
    CLR_RT_HeapBlock *storageFile;
    CLR_RT_HeapBlock *hbObj;
    SYSTEMTIME fileInfoTime;

    const char *workingPath;
    char workingDrive[DRIVE_LETTER_LENGTH];

    uint32_t startIndex;
    uint32_t maxItemsToRetrieve;
    uint32_t itemIndex = 0;

#if (NF_FEATURE_USE_SPIFFS == TRUE)
    spiffs *driveFs = NULL;
    int32_t driveIndex = -1;
#endif

#if ((HAL_USE_SDC == TRUE) || (HAL_USBH_USE_MSD == TRUE))

    DIR currentDirectory = {};
    FRESULT operationResult;
    static FILINFO fileInfo;
    uint16_t fileCount = 0;
    char *stringBuffer = NULL;
    char *workingBuffer = NULL;

    CLR_RT_HeapBlock &top = stack.PushValue();

    // get a pointer to the managed object instance and check that it's not NULL
    CLR_RT_HeapBlock *pThis = stack.This();
    FAULT_ON_NULL(pThis);

    // get start index
    startIndex = stack.Arg1().NumericByRef().u4;

    // get max items to retrieve
    maxItemsToRetrieve = stack.Arg2().NumericByRef().u4;

    // copy the first 2 letters of the path for the drive
    // path is 'D:\folder\file.txt', so we need 'D:'
    memcpy(
        workingDrive,
        pThis[Library_win_storage_native_Windows_Storage_StorageFolder::FIELD___path].DereferenceString()->StringText(),
        DRIVE_LETTER_LENGTH);

    // get a pointer to the path in managed field
    workingPath =
        pThis[Library_win_storage_native_Windows_Storage_StorageFolder::FIELD___path].DereferenceString()->StringText();

    // check if the working drive is the SPIFFS drive and...
    // ... that the path is the drive root (because SPIFFS doesn't support folders)
#if (NF_FEATURE_USE_SPIFFS == TRUE)
    if ((WORKING_DRIVE_IS_INTERNAL_DRIVE) && (hal_strlen_s(workingPath) == DRIVE_PATH_LENGTH - 1))
    {
        // get SPIFFS drive index...
        driveIndex = GetInternalDriveIndex(workingDrive);
        //... and pointer to the SPIFFS instance
        driveFs = hal_spiffs_get_fs_from_index(driveIndex);

        // this is the SPIFFS drive
        spiffs_DIR drive;
        memset(&drive, 0, sizeof(spiffs_DIR));

        struct spiffs_dirent e = {};
        struct spiffs_dirent *pe = &e;

        // need to perform this in two steps
        // 1st: count the file objects
        // 2nd: create the array items with each file object

        // perform 1st pass
        SPIFFS_opendir(driveFs, "/", &drive);
        while ((pe = SPIFFS_readdir(&drive, pe)))
        {
            fileCount++;
        }

        // have to close dir
        SPIFFS_closedir(&drive);
        memset(&drive, 0, sizeof(spiffs_DIR));

        // find <StorageFile> type, don't bother checking the result as it exists for sure
        g_CLR_RT_TypeSystem.FindTypeDef("StorageFile", "Windows.Storage", storageFileTypeDef);

        // create an array of <StorageFile>
        NANOCLR_CHECK_HRESULT(CLR_RT_HeapBlock_Array::CreateInstance(top, fileCount, storageFileTypeDef));

        // get a pointer to the first object in the array (which is of type <StorageFile>)
        storageFile = (CLR_RT_HeapBlock *)top.DereferenceArray()->GetFirstElement();

        if (fileCount > 0)
        {
            // allocate memory for buffer, if not already done
            if (workingBuffer == NULL)
            {
                workingBuffer = (char *)platform_malloc(2 * FF_LFN_BUF + 1);

                // sanity check for successful malloc
                if (workingBuffer == NULL)
                {
                    // failed to allocate memory
                    NANOCLR_SET_AND_LEAVE(CLR_E_OUT_OF_MEMORY);
                }
            }

            // perform 2nd pass
            // need to open the directory again
            SPIFFS_opendir(driveFs, "/", &drive);

            // and reset the file iterator vars too
            itemIndex = 0;
            fileCount = 0;
            e = {};
            pe = &e;

            while ((pe = SPIFFS_readdir(&drive, pe)))
            {
                // create an instance of <StorageFile>
                NANOCLR_CHECK_HRESULT(g_CLR_RT_ExecutionEngine.NewObjectFromIndex(*storageFile, storageFileTypeDef));

                // dereference the object in order to reach its fields
                hbObj = storageFile->Dereference();

                // file name
                NANOCLR_CHECK_HRESULT(CLR_RT_HeapBlock_String::CreateInstance(
                    hbObj[Library_win_storage_native_Windows_Storage_StorageFile::FIELD___name],
                    (const char *)pe->name));

                // clear working buffer
                memset(workingBuffer, 0, 2 * FF_LFN_BUF + 1);

                // compose file path
                CombinePath(workingBuffer, workingPath, (const char *)pe->name);

                NANOCLR_CHECK_HRESULT(CLR_RT_HeapBlock_String::CreateInstance(
                    hbObj[Library_win_storage_native_Windows_Storage_StorageFile::FIELD___path],
                    (const char *)workingBuffer));

                // SPIFFS files don't have date information

                // move the storage folder pointer to the next item in the array
                storageFile++;
            }

            // done here, close dir
            SPIFFS_closedir(&drive);
        }
    }
    else
#endif
    {
        // change drive
        if (f_chdrive(workingDrive) == FR_OK)
        {
            // open directory
            operationResult = f_opendir(&currentDirectory, workingPath);

            if (operationResult != FR_OK)
            {
                // error or directory empty
                // find <StorageFile> type, don't bother checking the result as it exists for sure
                g_CLR_RT_TypeSystem.FindTypeDef("StorageFile", "Windows.Storage", storageFileTypeDef);

                // create an array of <StorageFile>
                NANOCLR_CHECK_HRESULT(CLR_RT_HeapBlock_Array::CreateInstance(top, fileCount, storageFileTypeDef));
            }
            else
            {
                // need to perform this in two steps
                // 1st: count the file objects
                // 2nd: create the array items with each file object

                // perform 1st pass
                for (;;)
                {
                    // read next directory item
                    operationResult = f_readdir(&currentDirectory, &fileInfo);

                    // break on error or at end of dir
                    if (operationResult != FR_OK || fileInfo.fname[0] == 0)
                    {
                        break;
                    }

                    // check if this is a file
                    // but skip if:
                    // - has system attribute set
                    // - has hidden attribute set
                    if ((fileInfo.fattrib & AM_ARC) && !(fileInfo.fattrib & AM_SYS) && !(fileInfo.fattrib & AM_HID))
                    {
                        // check if this file is within the requested parameters
                        if ((itemIndex >= startIndex) && (fileCount < maxItemsToRetrieve))
                        {
                            fileCount++;
                        }

                        itemIndex++;
                    }
                }

                // find <StorageFile> type, don't bother checking the result as it exists for sure
                g_CLR_RT_TypeSystem.FindTypeDef("StorageFile", "Windows.Storage", storageFileTypeDef);

                // create an array of <StorageFile>
                NANOCLR_CHECK_HRESULT(CLR_RT_HeapBlock_Array::CreateInstance(top, fileCount, storageFileTypeDef));

                // get a pointer to the first object in the array (which is of type <StorageFile>)
                storageFile = (CLR_RT_HeapBlock *)top.DereferenceArray()->GetFirstElement();

                if (fileCount > 0)
                {
                    // allocate memory for buffers
                    stringBuffer = (char *)platform_malloc(FF_LFN_BUF + 1);
                    workingBuffer = (char *)platform_malloc(2 * FF_LFN_BUF + 1);

                    // sanity check for successful malloc
                    if (stringBuffer == NULL || workingBuffer == NULL)
                    {
                        // failed to allocate memory
                        NANOCLR_SET_AND_LEAVE(CLR_E_OUT_OF_MEMORY);
                    }

                    // perform 2nd pass
                    // need to rewind the directory read index first
                    f_readdir(&currentDirectory, NULL);

                    // and reset the file iterator vars too
                    itemIndex = 0;
                    fileCount = 0;

                    for (;;)
                    {
                        // read next directory item
                        operationResult = f_readdir(&currentDirectory, &fileInfo);

                        // break on error or at end of dir
                        if (operationResult != FR_OK || fileInfo.fname[0] == 0)
                        {
                            break;
                        }

                        // check if this is a file
                        // but skip if:
                        // - has system attribute set
                        // - has hidden attribute set
                        if ((fileInfo.fattrib & AM_ARC) && !(fileInfo.fattrib & AM_SYS) && !(fileInfo.fattrib & AM_HID))
                        {
                            // check if this file is within the requested parameters
                            if ((itemIndex >= startIndex) && (fileCount < maxItemsToRetrieve))
                            {
                                // create an instance of <StorageFile>
                                NANOCLR_CHECK_HRESULT(
                                    g_CLR_RT_ExecutionEngine.NewObjectFromIndex(*storageFile, storageFileTypeDef));

                                // dereference the object in order to reach its fields
                                hbObj = storageFile->Dereference();

                                // file name
                                NANOCLR_CHECK_HRESULT(CLR_RT_HeapBlock_String::CreateInstance(
                                    hbObj[Library_win_storage_native_Windows_Storage_StorageFile::FIELD___name],
                                    fileInfo.fname));

                                // clear working buffer
                                memset(workingBuffer, 0, 2 * FF_LFN_BUF + 1);

                                // compose file path
                                CombinePath(workingBuffer, workingPath, fileInfo.fname);

                                NANOCLR_CHECK_HRESULT(CLR_RT_HeapBlock_String::CreateInstance(
                                    hbObj[Library_win_storage_native_Windows_Storage_StorageFile::FIELD___path],
                                    workingBuffer));

                                // compute directory date
                                fileInfoTime = GetDateTime(fileInfo.fdate, fileInfo.ftime);

                                // get a reference to the dateCreated managed field...
                                CLR_RT_HeapBlock &dateFieldRef =
                                    hbObj[Library_win_storage_native_Windows_Storage_StorageFile::FIELD___dateCreated];
                                CLR_INT64 *pRes = (CLR_INT64 *)&dateFieldRef.NumericByRef().s8;
                                // ...and set it with the fileInfoTime
                                *pRes = HAL_Time_ConvertFromSystemTime(&fileInfoTime);

                                // move the storage folder pointer to the next item in the array
                                storageFile++;

                                // update iterator var
                                fileCount++;
                            }

                            // update iterator var
                            itemIndex++;
                        }
                    }
                }
                else
                {
                    // empty directory
                    // find <StorageFile> type, don't bother checking the result as it exists for sure
                    g_CLR_RT_TypeSystem.FindTypeDef("StorageFile", "Windows.Storage", storageFileTypeDef);

                    // create an array of <StorageFile>
                    NANOCLR_CHECK_HRESULT(CLR_RT_HeapBlock_Array::CreateInstance(top, fileCount, storageFileTypeDef));
                }
            }
        }
        else
        {
            // failed to change drive
            NANOCLR_SET_AND_LEAVE(CLR_E_VOLUME_NOT_FOUND);
        }
    }

#elif (NF_FEATURE_USE_SPIFFS == TRUE)

    CLR_RT_HeapBlock &top = stack.PushValue();

    // get a pointer to the managed object instance and check that it's not NULL
    CLR_RT_HeapBlock *pThis = stack.This();
    FAULT_ON_NULL(pThis);

    spiffs_DIR drive;
    struct spiffs_dirent e;
    struct spiffs_dirent *pe = &e;

    // get SPIFFS drive index...
    driveIndex = GetInternalDriveIndex(workingDrive);
    //... and pointer to the SPIFFS instance
    driveFs = hal_spiffs_get_fs_from_index(driveIndex);

    // need to perform this in two steps
    // 1st: count the file objects
    // 2nd: create the array items with each file object

    // perform 1st pass
    SPIFFS_opendir(driveFs, "/", &drive);
    while ((pe = SPIFFS_readdir(&drive, pe)))
    {
        fileCount++;
    }

    // have to close dir
    SPIFFS_closedir(&drive);

    // find <StorageFile> type, don't bother checking the result as it exists for sure
    g_CLR_RT_TypeSystem.FindTypeDef("StorageFile", "Windows.Storage", storageFileTypeDef);

    // create an array of <StorageFile>
    NANOCLR_CHECK_HRESULT(CLR_RT_HeapBlock_Array::CreateInstance(top, fileCount, storageFileTypeDef));

    // get a pointer to the first object in the array (which is of type <StorageFile>)
    storageFile = (CLR_RT_HeapBlock *)top.DereferenceArray()->GetFirstElement();

    if (fileCount > 0)
    {
        // allocate memory for buffer
        workingBuffer = (char *)platform_malloc(2 * FF_LFN_BUF + 1);

        // sanity check for successful malloc
        if (workingBuffer == NULL)
        {
            // failed to allocate memory
            NANOCLR_SET_AND_LEAVE(CLR_E_OUT_OF_MEMORY);
        }

        // perform 2nd pass
        // need to open the directory again
        SPIFFS_opendir(driveFs, "/", &drive);

        // and reset the file iterator vars too
        itemIndex = 0;
        fileCount = 0;

        while ((pe = SPIFFS_readdir(&drive, pe)))
        {
            // create an instance of <StorageFile>
            NANOCLR_CHECK_HRESULT(g_CLR_RT_ExecutionEngine.NewObjectFromIndex(*storageFile, storageFileTypeDef));

            // dereference the object in order to reach its fields
            hbObj = storageFile->Dereference();

            // file name
            NANOCLR_CHECK_HRESULT(CLR_RT_HeapBlock_String::CreateInstance(
                hbObj[Library_win_storage_native_Windows_Storage_StorageFile::FIELD___name],
                (const char *)pe->name));

            // clear working buffer
            memset(workingBuffer, 0, 2 * FF_LFN_BUF + 1);

            // compose file path
            CombinePath(workingBuffer, workingPath, (const char *)pe->name);

            NANOCLR_CHECK_HRESULT(CLR_RT_HeapBlock_String::CreateInstance(
                hbObj[Library_win_storage_native_Windows_Storage_StorageFile::FIELD___path],
                workingBuffer));

            // SPIFFS files don't have date information

            // move the storage folder pointer to the next item in the array
            storageFile++;
        }

        // done here, close dir
        SPIFFS_closedir(&drive);
    }
#endif

    NANOCLR_CLEANUP();

#if ((HAL_USE_SDC == TRUE) || (HAL_USBH_USE_MSD == TRUE))

    // close directory, if it was ever opened
    if (currentDirectory.dir)
    {
        f_closedir(&currentDirectory);
    }

#endif

    // free buffers memory, if allocated
    if (stringBuffer != NULL)
    {
        platform_free(stringBuffer);
    }
    if (workingBuffer != NULL)
    {
        platform_free(workingBuffer);
    }

    NANOCLR_CLEANUP_END();
}

HRESULT Library_win_storage_native_Windows_Storage_StorageFolder::
    CreateFileNative___WindowsStorageStorageFile__STRING__U4(CLR_RT_StackFrame &stack)
{
    NANOCLR_HEADER();

    CLR_RT_TypeDef_Index storageFileTypeDef;
    CLR_RT_HeapBlock *storageFile;

    const char *fileName;
    const char *workingPath;
    char workingDrive[DRIVE_LETTER_LENGTH];

    CreationCollisionOption options;

#if (NF_FEATURE_USE_SPIFFS == TRUE)
    spiffs *driveFs = NULL;
    int32_t driveIndex;
#endif

#if ((HAL_USE_SDC == TRUE) || (HAL_USBH_USE_MSD == TRUE))

    FIL file;
    static FILINFO fileInfo;
    SYSTEMTIME fileInfoTime;
    FRESULT operationResult;
    uint8_t modeFlags = 0;
    char *filePath = NULL;

    // get a pointer to the managed object instance and check that it's not NULL
    CLR_RT_HeapBlock *pThis = stack.This();
    FAULT_ON_NULL(pThis);

    // copy the first 2 letters of the path for the drive
    // path is 'D:\folder\file.txt', so we need 'D:'
    memcpy(
        workingDrive,
        pThis[Library_win_storage_native_Windows_Storage_StorageFolder::FIELD___path].DereferenceString()->StringText(),
        DRIVE_LETTER_LENGTH);

    // get creation collision options
    options = (CreationCollisionOption)stack.Arg2().NumericByRef().u4;

    // get a pointer to the StorageFolder path in managed field
    workingPath =
        pThis[Library_win_storage_native_Windows_Storage_StorageFolder::FIELD___path].DereferenceString()->StringText();

    // get a pointer to the desired file name
    fileName = stack.Arg1().DereferenceString()->StringText();

    // setup file path
    filePath = (char *)platform_malloc(2 * FF_LFN_BUF + 1);

    // sanity check for successful malloc
    if (filePath == NULL)
    {
        // failed to allocate memory
        NANOCLR_SET_AND_LEAVE(CLR_E_OUT_OF_MEMORY);
    }

    // clear working buffer
    memset(filePath, 0, 2 * FF_LFN_BUF + 1);

    // compose file path
    CombinePath(filePath, workingPath, fileName);

    // change directory
    operationResult = f_chdir(workingPath);

    if (operationResult != FR_OK)
    {
        if (operationResult == FR_INVALID_DRIVE)
        {
            // check if the working drive is the SPIFFS drive
#if (NF_FEATURE_USE_SPIFFS == TRUE)
            if (WORKING_DRIVE_IS_INTERNAL_DRIVE)
            {
                // this is the SPIFFS drive

                // get SPIFFS drive index...
                driveIndex = GetInternalDriveIndex(workingDrive);
                //... and pointer to the SPIFFS instance
                driveFs = hal_spiffs_get_fs_from_index(driveIndex);

                // proceed to create the file

                // compute mode flags from CreationCollisionOption
                switch (options)
                {
                    case CreationCollisionOption_ReplaceExisting:
                        modeFlags = SPIFFS_CREAT | SPIFFS_TRUNC | SPIFFS_RDWR;
                        break;

                    case CreationCollisionOption_FailIfExists:
                        modeFlags = SPIFFS_RDWR;
                        break;

                    case CreationCollisionOption_OpenIfExists:
                        modeFlags = SPIFFS_CREAT | SPIFFS_RDWR;
                        break;

                    case CreationCollisionOption_GenerateUniqueName:
                        // this operation is not supported in nanoFramework
                        NANOCLR_SET_AND_LEAVE(CLR_E_INVALID_PARAMETER);
                        break;

                    default:
                        break;
                }

                spiffs_file fd = SPIFFS_open(driveFs, fileName, modeFlags, 0);
                if (fd < 0)
                {
                    int32_t error = SPIFFS_errno(driveFs);

                    // process operation result according to creation options
                    if ((error == SPIFFS_ERR_FILE_EXISTS) && (options == CreationCollisionOption_FailIfExists))
                    {
                        // file already exists
                        NANOCLR_SET_AND_LEAVE(CLR_E_PATH_ALREADY_EXISTS);
                    }
                    if (options == CreationCollisionOption_OpenIfExists)
                    {
                        // file doesn't exist
                        NANOCLR_SET_AND_LEAVE(CLR_E_FILE_NOT_FOUND);
                    }

                    // failed to create the file
                    NANOCLR_SET_AND_LEAVE(CLR_E_FILE_IO);
                }
                else
                {
                    // file created (or opened) successfully
                    // OK to close it
                    SPIFFS_close(driveFs, fd);

                    // compose return object
                    // find <StorageFile> type, don't bother checking the result as it exists for sure
                    g_CLR_RT_TypeSystem.FindTypeDef("StorageFile", "Windows.Storage", storageFileTypeDef);

                    // create a <StorageFile>
                    NANOCLR_CHECK_HRESULT(
                        g_CLR_RT_ExecutionEngine.NewObjectFromIndex(stack.PushValue(), storageFileTypeDef));

                    // get a handle to the storage file
                    storageFile = stack.TopValue().Dereference();

                    // file name
                    NANOCLR_CHECK_HRESULT(CLR_RT_HeapBlock_String::CreateInstance(
                        storageFile[Library_win_storage_native_Windows_Storage_StorageFile::FIELD___name],
                        fileName));

                    NANOCLR_CHECK_HRESULT(CLR_RT_HeapBlock_String::CreateInstance(
                        storageFile[Library_win_storage_native_Windows_Storage_StorageFile::FIELD___path],
                        filePath));

                    // SPIFFS don't have date time details, so we are done here
                }
            }
            else
            {
#else
            {
#endif
                // invalid drive
                NANOCLR_SET_AND_LEAVE(CLR_E_VOLUME_NOT_FOUND);
            }
        }
        else
        {
            // error opening the directory
            NANOCLR_SET_AND_LEAVE(CLR_E_DIRECTORY_NOT_FOUND);
        }
    }
    else
    {
        // compute mode flags from CreationCollisionOption
        switch (options)
        {
            case CreationCollisionOption_ReplaceExisting:
                modeFlags = FA_CREATE_ALWAYS;
                break;

            case CreationCollisionOption_FailIfExists:
                modeFlags = FA_CREATE_NEW;
                break;

            case CreationCollisionOption_OpenIfExists:
                modeFlags = FA_OPEN_EXISTING;
                break;

            case CreationCollisionOption_GenerateUniqueName:
                // this operation is not supported in nanoFramework
                NANOCLR_SET_AND_LEAVE(CLR_E_INVALID_PARAMETER);
                break;

            default:
                break;
        }

        // open file
        operationResult = f_open(&file, filePath, modeFlags);

        // process operation result according to creation options
        if ((operationResult == FR_EXIST) && (options == CreationCollisionOption_FailIfExists))
        {
            // file already exists
            NANOCLR_SET_AND_LEAVE(CLR_E_PATH_ALREADY_EXISTS);
        }
        if ((operationResult == FR_NO_FILE) && (options == CreationCollisionOption_OpenIfExists))
        {
            // file doesn't exist
            NANOCLR_SET_AND_LEAVE(CLR_E_FILE_NOT_FOUND);
        }

        if (operationResult == FR_OK)
        {
            // file created (or opened) successfully
            // OK to close it
            f_close(&file);

            // now get the details
            f_stat(fileName, &fileInfo);

            // compose return object
            // find <StorageFile> type, don't bother checking the result as it exists for sure
            g_CLR_RT_TypeSystem.FindTypeDef("StorageFile", "Windows.Storage", storageFileTypeDef);

            // create a <StorageFile>
            NANOCLR_CHECK_HRESULT(g_CLR_RT_ExecutionEngine.NewObjectFromIndex(stack.PushValue(), storageFileTypeDef));

            // get a handle to the storage file
            storageFile = stack.TopValue().Dereference();

            // file name
            NANOCLR_CHECK_HRESULT(CLR_RT_HeapBlock_String::CreateInstance(
                storageFile[Library_win_storage_native_Windows_Storage_StorageFile::FIELD___name],
                fileName));

            NANOCLR_CHECK_HRESULT(CLR_RT_HeapBlock_String::CreateInstance(
                storageFile[Library_win_storage_native_Windows_Storage_StorageFile::FIELD___path],
                filePath));

            // get the date time details and fill in the managed field
            // compute directory date
            fileInfoTime = GetDateTime(fileInfo.fdate, fileInfo.ftime);

            // Save fileInfoTime to StorageFile date created field...
            SaveDateTimeToField(
                storageFile,
                Library_win_storage_native_Windows_Storage_StorageFile::FIELD___dateCreated,
                HAL_Time_ConvertFromSystemTime(&fileInfoTime));
        }
        else
        {
            // failed to create the file
            NANOCLR_SET_AND_LEAVE(CLR_E_FILE_IO);
        }
    }

#elif (NF_FEATURE_USE_SPIFFS == TRUE)

    // get a pointer to the managed object instance and check that it's not NULL
    CLR_RT_HeapBlock *pThis = stack.This();
    FAULT_ON_NULL(pThis);

    // copy the first 2 letters of the path for the drive
    // path is 'D:\folder\file.txt', so we need 'D:'
    memcpy(
        workingDrive,
        pThis[Library_win_storage_native_Windows_Storage_StorageFolder::FIELD___path].DereferenceString()->StringText(),
        DRIVE_LETTER_LENGTH);

    // get creation collision options
    options = (CreationCollisionOption)stack.Arg2().NumericByRef().u4;

    // get a pointer to the StorageFolder path in managed field
    workingPath =
        pThis[Library_win_storage_native_Windows_Storage_StorageFolder::FIELD___path].DereferenceString()->StringText();

    // get a pointer to the desired file name
    fileName = stack.Arg1().DereferenceString()->StringText();

    // setup file path
    filePath = (char *)platform_malloc(2 * FF_LFN_BUF + 1);

    // sanity check for successful malloc
    if (filePath == NULL)
    {
        // failed to allocate memory
        NANOCLR_SET_AND_LEAVE(CLR_E_OUT_OF_MEMORY);
    }

    // clear working buffer
    memset(filePath, 0, 2 * FF_LFN_BUF + 1);

    // compose file path
    CombinePath(filePath, workingPath, fileName);

    // compute mode flags from CreationCollisionOption
    switch (options)
    {
        case CreationCollisionOption_ReplaceExisting:
            modeFlags = SPIFFS_CREAT | SPIFFS_TRUNC;
            break;

        case CreationCollisionOption_FailIfExists:
            modeFlags = 0;
            break;

        case CreationCollisionOption_OpenIfExists:
            modeFlags = SPIFFS_CREAT;
            break;

        case CreationCollisionOption_GenerateUniqueName:
            // this operation is not supported in nanoFramework
            NANOCLR_SET_AND_LEAVE(CLR_E_INVALID_PARAMETER);
            break;

        default:
            break;
    }

    spiffs_file fd = SPIFFS_open(driveFs, filePath, modeFlags, 0);
    if (fd < 0)
    {
        int32_t error = SPIFFS_errno(driveFs);

        // process operation result according to creation options
        if ((error == SPIFFS_ERR_FILE_EXISTS) && (options == CreationCollisionOption_FailIfExists))
        {
            // file already exists
            NANOCLR_SET_AND_LEAVE(CLR_E_PATH_ALREADY_EXISTS);
        }
        if (options == CreationCollisionOption_OpenIfExists)
        {
            // file doesn't exist
            NANOCLR_SET_AND_LEAVE(CLR_E_FILE_NOT_FOUND);
        }

        // failed to create the file
        NANOCLR_SET_AND_LEAVE(CLR_E_FILE_IO);
    }
    else
    {
        // file created (or opened) successfully
        // OK to close it
        SPIFFS_close(driveFs, fd);

        // compose return object
        // find <StorageFile> type, don't bother checking the result as it exists for sure
        g_CLR_RT_TypeSystem.FindTypeDef("StorageFile", "Windows.Storage", storageFileTypeDef);

        // create a <StorageFile>
        NANOCLR_CHECK_HRESULT(g_CLR_RT_ExecutionEngine.NewObjectFromIndex(stack.PushValue(), storageFileTypeDef));

        // get a handle to the storage file
        storageFile = stack.TopValue().Dereference();

        // file name
        NANOCLR_CHECK_HRESULT(CLR_RT_HeapBlock_String::CreateInstance(
            storageFile[Library_win_storage_native_Windows_Storage_StorageFile::FIELD___name],
            fileName));

        NANOCLR_CHECK_HRESULT(CLR_RT_HeapBlock_String::CreateInstance(
            storageFile[Library_win_storage_native_Windows_Storage_StorageFile::FIELD___path],
            filePath));

        // SPIFFS don't have date time details, so we are done here
    }
#endif

    NANOCLR_CLEANUP();

    // free buffer memory, if allocated
    if (filePath != NULL)
    {
        platform_free(filePath);
    }

    NANOCLR_CLEANUP_END();
}

HRESULT Library_win_storage_native_Windows_Storage_StorageFolder::
    CreateFolderNative___WindowsStorageStorageFolder__STRING__U4(CLR_RT_StackFrame &stack)
{
    NANOCLR_HEADER();

    CLR_RT_TypeDef_Index storageFolderTypeDef;
    CLR_RT_HeapBlock *storageFolder;

    const char *folderName;
    const char *workingPath;
    char workingDrive[DRIVE_LETTER_LENGTH];

    CreationCollisionOption options;

#if ((HAL_USE_SDC == TRUE) || (HAL_USBH_USE_MSD == TRUE))

    static FILINFO fileInfo;
    SYSTEMTIME fileInfoTime;
    FRESULT operationResult;
    char *folderPath = NULL;

    // get a pointer to the managed object instance and check that it's not NULL
    CLR_RT_HeapBlock *pThis = stack.This();
    FAULT_ON_NULL(pThis);

    // copy the first 2 letters of the path for the drive
    // path is 'D:\folder\file.txt', so we need 'D:'
    memcpy(
        workingDrive,
        pThis[Library_win_storage_native_Windows_Storage_StorageFolder::FIELD___path].DereferenceString()->StringText(),
        DRIVE_LETTER_LENGTH);

    // get creation collision options
    options = (CreationCollisionOption)stack.Arg2().NumericByRef().u4;

    // get a pointer to the path in managed field
    workingPath =
        pThis[Library_win_storage_native_Windows_Storage_StorageFolder::FIELD___path].DereferenceString()->StringText();

    // get a pointer to the desired folder name
    folderName = stack.Arg1().DereferenceString()->StringText();

    folderPath = (char *)platform_malloc(2 * FF_LFN_BUF + 1);

    // sanity check for successful malloc
    if (folderPath == NULL)
    {
        // failed to allocate memory
        NANOCLR_SET_AND_LEAVE(CLR_E_OUT_OF_MEMORY);
    }

    // clear working buffer
    memset(folderPath, 0, 2 * FF_LFN_BUF + 1);

    // compose folder path
    CombinePath(folderPath, workingPath, folderName);

    // check if folder exists
    operationResult = f_stat(folderPath, &fileInfo);

    // folder doesn't exist
    if (operationResult == FR_NO_FILE)
    {
        if (options == CreationCollisionOption_OpenIfExists)
        {
            // folder doesn't exist
            NANOCLR_SET_AND_LEAVE(CLR_E_DIRECTORY_NOT_FOUND);
        }
        else
        {
            // create directory
            operationResult = f_mkdir(folderPath);

            if (operationResult == FR_OK)
            {
                operationResult = f_stat(folderPath, &fileInfo);
            }
            else
            {
                // failed to create the folder
                NANOCLR_SET_AND_LEAVE(CLR_E_FILE_IO);
            }
        }
    }
    else
    {
        if (options == CreationCollisionOption_FailIfExists)
        {
            // folder already exists
            NANOCLR_SET_AND_LEAVE(CLR_E_PATH_ALREADY_EXISTS);
        }
    }

    if (operationResult == FR_OK)
    {
        // compose return object
        // find <StorageFolder> type, don't bother checking the result as it exists for sure
        g_CLR_RT_TypeSystem.FindTypeDef("StorageFolder", "Windows.Storage", storageFolderTypeDef);

        // create a <StorageFolder>
        NANOCLR_CHECK_HRESULT(g_CLR_RT_ExecutionEngine.NewObjectFromIndex(stack.PushValue(), storageFolderTypeDef));

        // get a handle to the storage folder
        storageFolder = stack.TopValue().Dereference();

        // folder name
        NANOCLR_CHECK_HRESULT(CLR_RT_HeapBlock_String::CreateInstance(
            storageFolder[Library_win_storage_native_Windows_Storage_StorageFolder::FIELD___name],
            folderName));

        NANOCLR_CHECK_HRESULT(CLR_RT_HeapBlock_String::CreateInstance(
            storageFolder[Library_win_storage_native_Windows_Storage_StorageFolder::FIELD___path],
            folderPath));

        // get the date time details and fill in the managed field
        // compute directory date
        fileInfoTime = GetDateTime(fileInfo.fdate, fileInfo.ftime);

        // Save fileInfoTime to StorageFolder date created field...
        SaveDateTimeToField(
            storageFolder,
            Library_win_storage_native_Windows_Storage_StorageFolder::FIELD___dateCreated,
            HAL_Time_ConvertFromSystemTime(&fileInfoTime));
    }
    else
    {
        // failed to get folder details
        NANOCLR_SET_AND_LEAVE(CLR_E_FILE_IO);
    }

#elif (NF_FEATURE_USE_SPIFFS == TRUE)

    // throw not supported exception because folders aren't supported in SPIFFS
    NANOCLR_SET_AND_LEAVE(CLR_E_NOT_SUPPORTED);

#endif

    NANOCLR_CLEANUP();

    // free buffer memory, if allocated
    if (folderPath != NULL)
    {
        platform_free(folderPath);
    }

    NANOCLR_CLEANUP_END();
}

HRESULT Library_win_storage_native_Windows_Storage_StorageFolder::DeleteFolderNative___VOID(CLR_RT_StackFrame &stack)
{
    NANOCLR_HEADER();

    const char *workingPath;
    // need extra room for the change dir command
    char workingDrive[DRIVE_LETTER_LENGTH + 2];

#if ((HAL_USE_SDC == TRUE) || (HAL_USBH_USE_MSD == TRUE))

    FRESULT operationResult;

    // get a pointer to the managed object instance and check that it's not NULL
    CLR_RT_HeapBlock *pThis = stack.This();
    FAULT_ON_NULL(pThis);

    // get a pointer to the path in managed field
    workingPath =
        pThis[Library_win_storage_native_Windows_Storage_StorageFolder::FIELD___path].DereferenceString()->StringText();

    // remove folder
    operationResult = f_unlink(workingPath);
    if (operationResult == FR_INVALID_NAME)
    {
        // Invalid path
        NANOCLR_SET_AND_LEAVE(CLR_E_INVALID_PARAMETER);
    }
    else if (operationResult == FR_DENIED)
    {
        // this could be because the folder is not empty or because it's the current folder

        // change directory to the parent directory using f_chdir("2:..")

        // copy the first 2 letters of the path for the drive
        // path is 'D:\folder\file.txt', so we need 'D:'
        memcpy(
            workingDrive,
            pThis[Library_win_storage_native_Windows_Storage_StorageFolder::FIELD___path]
                .DereferenceString()
                ->StringText(),
            DRIVE_LETTER_LENGTH);
        // make sure there is a terminator
        workingDrive[2] = '\0';
        strcat(workingDrive, "..");

        // change dir to parent
        operationResult = f_chdir(workingDrive);

        // try remove again
        operationResult = f_unlink(workingPath);

        if (operationResult == FR_DENIED)
        {
            // folder not empty
            NANOCLR_SET_AND_LEAVE(CLR_E_DIRECTORY_NOT_EMPTY);
        }
        else if (operationResult != FR_OK)
        {
            // something else is failing
            NANOCLR_SET_AND_LEAVE(CLR_E_FILE_IO);
        }
    }
    else if (operationResult != FR_OK)
    {
        // folder doesn't exist
#if (NF_FEATURE_USE_SPIFFS == TRUE)
        if (WORKING_DRIVE_IS_INTERNAL_DRIVE)
        {
            // this is the SPIFFS drive
            // throw not supported exception because folders aren't supported in SPIFFS
            NANOCLR_SET_AND_LEAVE(CLR_E_NOT_SUPPORTED);
        }
        else
        {
#else
        {
#endif
            NANOCLR_SET_AND_LEAVE(CLR_E_DIRECTORY_NOT_FOUND);
        }
    }

#elif (NF_FEATURE_USE_SPIFFS == TRUE)

    // throw not supported exception because folders aren't supported in SPIFFS
    NANOCLR_SET_AND_LEAVE(CLR_E_NOT_SUPPORTED);

#endif

    NANOCLR_CLEANUP();

    NANOCLR_CLEANUP_END();
}

HRESULT Library_win_storage_native_Windows_Storage_StorageFolder::RenameFolderNative___VOID__STRING(
    CLR_RT_StackFrame &stack)
{
    NANOCLR_HEADER();

    const char *workingPath;
    const char *desiredPath;
    char workingDrive[DRIVE_LETTER_LENGTH];

#if ((HAL_USE_SDC == TRUE) || (HAL_USBH_USE_MSD == TRUE))

    FRESULT operationResult;

    // get a pointer to the managed object instance and check that it's not NULL
    CLR_RT_HeapBlock *pThis = stack.This();
    FAULT_ON_NULL(pThis);

    // copy the first 2 letters of the path for the drive
    // path is 'D:\folder\file.txt', so we need 'D:'
    memcpy(
        workingDrive,
        pThis[Library_win_storage_native_Windows_Storage_StorageFolder::FIELD___path].DereferenceString()->StringText(),
        DRIVE_LETTER_LENGTH);

    // get a pointer to the path in managed field
    workingPath =
        pThis[Library_win_storage_native_Windows_Storage_StorageFolder::FIELD___path].DereferenceString()->StringText();

    // get a pointer to the desired folder name
    desiredPath = stack.Arg1().DereferenceString()->StringText();

    // rename folder
    operationResult = f_rename(workingPath, desiredPath);
    if (operationResult == FR_INVALID_NAME)
    {
        // invalid path
        NANOCLR_SET_AND_LEAVE(CLR_E_INVALID_PARAMETER);
    }
    else if (operationResult != FR_OK)
    {
        // folder doesn't exist
#if (NF_FEATURE_USE_SPIFFS == TRUE)
        if (WORKING_DRIVE_IS_INTERNAL_DRIVE)
        {
            // this is the SPIFFS drive
            // throw not supported exception because folders aren't supported in SPIFFS
            NANOCLR_SET_AND_LEAVE(CLR_E_NOT_SUPPORTED);
        }
        else
        {
#else
        {
#endif
            NANOCLR_SET_AND_LEAVE(CLR_E_DIRECTORY_NOT_FOUND);
        }
    }

#elif (NF_FEATURE_USE_SPIFFS == TRUE)

    // throw not supported exception because folders aren't supported in SPIFFS
    NANOCLR_SET_AND_LEAVE(CLR_E_NOT_SUPPORTED);

#endif

    NANOCLR_CLEANUP();

    NANOCLR_CLEANUP_END();
}

HRESULT Library_win_storage_native_Windows_Storage_StorageFolder::GetFolderNative___WindowsStorageStorageFolder__STRING(
    CLR_RT_StackFrame &stack)
{
    NANOCLR_HEADER();

    CLR_RT_TypeDef_Index storageFolderTypeDef;
    CLR_RT_HeapBlock *storageFolder;

    const char *folderName;
    const char *workingPath;
    char *folderPath = NULL;

#if (NF_FEATURE_USE_SPIFFS == TRUE)
    char workingDrive[DRIVE_LETTER_LENGTH];
#endif

#if ((HAL_USE_SDC == TRUE) || (HAL_USBH_USE_MSD == TRUE))

    FILINFO fileInfo;
    SYSTEMTIME fileInfoTime;

    FRESULT operationResult;

    // get a pointer to the managed object instance and check that it's not NULL
    CLR_RT_HeapBlock *pThis = stack.This();
    FAULT_ON_NULL(pThis);

    // get a pointer to the path in managed field
    workingPath =
        pThis[Library_win_storage_native_Windows_Storage_StorageFolder::FIELD___path].DereferenceString()->StringText();

    // get a pointer to the desired folder name
    folderName = stack.Arg1().DereferenceString()->StringText();

    folderPath = (char *)platform_malloc(2 * FF_LFN_BUF + 1);

    // sanity check for successful malloc
    if (folderPath == NULL)
    {
        // failed to allocate memory
        NANOCLR_SET_AND_LEAVE(CLR_E_OUT_OF_MEMORY);
    }

    // clear working buffer
    memset(folderPath, 0, 2 * FF_LFN_BUF + 1);

    // compose folder path
    CombinePath(folderPath, workingPath, folderName);

    // check if directory exists
    operationResult = f_stat(folderPath, &fileInfo);
    if (operationResult != FR_OK)
    {
        // folder doesn't exist
#if (NF_FEATURE_USE_SPIFFS == TRUE)
        if (WORKING_DRIVE_IS_INTERNAL_DRIVE)
        {
            // this is the SPIFFS drive
            // throw not supported exception because folders aren't supported in SPIFFS
            NANOCLR_SET_AND_LEAVE(CLR_E_NOT_SUPPORTED);
        }
        else
        {
#else
        {
#endif
            NANOCLR_SET_AND_LEAVE(CLR_E_DIRECTORY_NOT_FOUND);
        }
    }
    else
    {
        // is this a file?
        if (!(fileInfo.fattrib & AM_DIR))
        {
            // Path represents a file
            NANOCLR_SET_AND_LEAVE(CLR_E_DIRECTORY_NOT_FOUND);
        }
        else
        {
            // compose return object
            // find <StorageFolder> type, don't bother checking the result as it exists for sure
            g_CLR_RT_TypeSystem.FindTypeDef("StorageFolder", "Windows.Storage", storageFolderTypeDef);

            // create a <StorageFolder>
            NANOCLR_CHECK_HRESULT(g_CLR_RT_ExecutionEngine.NewObjectFromIndex(stack.PushValue(), storageFolderTypeDef));

            // get a handle to the storage folder
            storageFolder = stack.TopValue().Dereference();

            // folder name
            NANOCLR_CHECK_HRESULT(CLR_RT_HeapBlock_String::CreateInstance(
                storageFolder[Library_win_storage_native_Windows_Storage_StorageFolder::FIELD___name],
                folderName));

            NANOCLR_CHECK_HRESULT(CLR_RT_HeapBlock_String::CreateInstance(
                storageFolder[Library_win_storage_native_Windows_Storage_StorageFolder::FIELD___path],
                folderPath));

            // get the date time details and fill in the managed field
            // compute directory date
            fileInfoTime = GetDateTime(fileInfo.fdate, fileInfo.ftime);

            // Save fileInfoTime to StorageFolder date created field...
            SaveDateTimeToField(
                storageFolder,
                Library_win_storage_native_Windows_Storage_StorageFolder::FIELD___dateCreated,
                HAL_Time_ConvertFromSystemTime(&fileInfoTime));
        }
    }

#elif (NF_FEATURE_USE_SPIFFS == TRUE)

    // throw not supported exception because folders aren't supported in SPIFFS
    NANOCLR_SET_AND_LEAVE(CLR_E_NOT_SUPPORTED);

#endif

    NANOCLR_CLEANUP();

    // free buffer memory, if allocated
    if (folderPath != NULL)
    {
        platform_free(folderPath);
    }

    NANOCLR_CLEANUP_END();
}


text:
namespace egl
{
class Surface;
}

namespace gl
{
class Framebuffer;
struct PixelUnpackState;
struct SamplerState;
}

namespace rx
{

class Image;
class Renderer;
class TextureStorage;

class TextureImpl
{
  public:
    virtual ~TextureImpl() {};

    // TODO: If this methods could go away that would be ideal;
    // TextureStorage should only be necessary for the D3D backend, and as such
    // higher level code should not rely on it.
    virtual TextureStorage *getNativeTexture() = 0;

    // Deprecated in favour of the ImageIndex method
    virtual Image *getImage(int level, int layer) const = 0;
    virtual Image *getImage(const gl::ImageIndex &index) const = 0;
    virtual GLsizei getLayerCount(int level) const = 0;

    virtual void setUsage(GLenum usage) = 0;

    virtual void setImage(GLenum target, GLint level, GLsizei width, GLsizei height, GLsizei depth, GLenum internalFormat, GLenum format, GLenum type, const gl::PixelUnpackState &unpack, const void *pixels) = 0;
    virtual void setCompressedImage(GLenum target, GLint level, GLenum format, GLsizei width, GLsizei height, GLsizei depth, GLsizei imageSize, const void *pixels) = 0;
    virtual void subImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, const gl::PixelUnpackState &unpack, const void *pixels) = 0;
    virtual void subImageCompressed(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLsizei imageSize, const void *pixels) = 0;
    virtual void copyImage(GLenum target, GLint level, GLenum format, GLint x, GLint y, GLsizei width, GLsizei height, gl::Framebuffer *source) = 0;
    virtual void copySubImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height, gl::Framebuffer *source) = 0;
    virtual void storage(GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth) = 0;

    virtual void generateMipmaps() = 0;

    virtual void bindTexImage(egl::Surface *surface) = 0;
    virtual void releaseTexImage() = 0;
};

}

#endif // LIBGLESV2_RENDERER_TEXTUREIMPL_H_

redpajama_set_name: RedPajamaGithub


text:
//_WIN32_WINNT must be defined to 0x0501 (or above) before including windows.h
//These files must be included in your project, preferably in stdafx.h if this is a Visual C++ Project
#include <tchar.h>		//Used for ANSI/Unicode compatibility
#include <map>			//Used internally by the class
#include <uxtheme.h>	//Used to access the UxTheme library

#if WINVER >= 0x600
#include <vssym32.h>
#else
#include <tmschema.h>	//Definitions used by some of the UxTheme library functions
#endif

class CRichEditThemed final
{
public:
	//This function must be called during the creation of your window, like in WM_INITDIALOG or WM_CREATE
	//It MUST be called before the richedit control is displayed for the first time
	static bool Attach(HWND hRichEdit);

private:
	explicit CRichEditThemed(HWND hRichEdit);
	~CRichEditThemed();

	CRichEditThemed() = delete;
	CRichEditThemed(const CRichEditThemed &) = delete;
	CRichEditThemed(CRichEditThemed &&) = delete;
	CRichEditThemed &operator =(const CRichEditThemed &) = delete;
	CRichEditThemed &operator =(CRichEditThemed &&) = delete;

	void VerifyThemedBorderState() noexcept;
	bool OnNCPaint() noexcept;
	bool OnNCCalcSize(NCCALCSIZE_PARAMS *csparam) noexcept;

	static bool InitLibrary() noexcept;
	static LRESULT CALLBACK RichEditStyledProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam);

private:
	static inline std::map<HWND,CRichEditThemed*> m_aInstances;

	HWND m_hRichEdit{ nullptr };
	WNDPROC m_pOriginalWndProc{ nullptr };
	bool m_bThemedBorder{ false };
	RECT m_rcClientPos{ 0,0,0,0 };

	//Function pointers from the UxTheme library
	static inline HMODULE m_hUxTheme{ nullptr };
	static HTHEME (WINAPI *pOpenThemeData)(HWND, LPCWSTR);
	static HRESULT (WINAPI *pCloseThemeData)(HTHEME);
	static HRESULT (WINAPI *pDrawThemeBackground)(HTHEME, HDC, int, int, const RECT*, const RECT *);
	static HRESULT (WINAPI *pGetThemeBackgroundContentRect)(HTHEME, HDC, int, int,  const RECT *, RECT *);
	static BOOL (WINAPI *pIsThemeActive)();
	static BOOL (WINAPI *pIsThemeBackgroundPartiallyTransparent)(HTHEME, int, int);
	static HRESULT (WINAPI *pDrawThemeParentBackground)(HWND, HDC, RECT*);
};


text: tsc collections.ts -d


text:
// DebugPlotViewerView.cpp : implementation of the CDebugPlotViewerView class
//

#include "stdafx.h"
// SHARED_HANDLERS can be defined in an ATL project implementing preview, thumbnail
// and search filter handlers and allows sharing of document code with that project.
#ifndef SHARED_HANDLERS
#include "DebugPlotViewer.h"
#endif

#include "DebugPlotViewerDoc.h"
#include "DebugPlotViewerView.h"

#include <algorithm>
#include "Logger.h"
#include "AppMessage.h"

#ifdef _DEBUG
#define new DEBUG_NEW
#endif

// CDebugPlotViewerView

IMPLEMENT_DYNCREATE(CDebugPlotViewerView, CView)

BEGIN_MESSAGE_MAP(CDebugPlotViewerView, CView)
	// Standard printing commands
	ON_COMMAND(ID_FILE_PRINT, &CView::OnFilePrint)
	ON_COMMAND(ID_FILE_PRINT_DIRECT, &CView::OnFilePrint)
	ON_COMMAND(ID_FILE_PRINT_PREVIEW, &CDebugPlotViewerView::OnFilePrintPreview)
	ON_WM_CONTEXTMENU()
	ON_WM_RBUTTONUP()

	ON_WM_MOUSEMOVE()
	ON_WM_LBUTTONUP()
	ON_WM_CREATE()

	ON_MESSAGE(WM_APP, OnApp)
	ON_WM_SIZE()
END_MESSAGE_MAP()

// CDebugPlotViewerView construction/destruction

CDebugPlotViewerView::CDebugPlotViewerView()
{
	// TODO: add construction code here
}

CDebugPlotViewerView::~CDebugPlotViewerView()
{

}

BOOL CDebugPlotViewerView::PreCreateWindow(CREATESTRUCT& cs)
{
	// TODO: Modify the Window class or styles here by modifying
	//  the CREATESTRUCT cs
	//cs.style &=~(WS_THICKFRAME | WS_BORDER);

	return CView::PreCreateWindow(cs);
}

// CDebugPlotViewerView drawing

void CDebugPlotViewerView::OnDraw(CDC* /*pDC*/)
{
	CDebugPlotViewerDoc* pDoc = GetDocument();
	ASSERT_VALID(pDoc);
	if (!pDoc)
		return;

	// TODO: add draw code for native data here
}

// CDebugPlotViewerView printing

void CDebugPlotViewerView::OnFilePrintPreview()
{
//#ifndef SHARED_HANDLERS
//	AFXPrintPreview(this);
//#endif
}

BOOL CDebugPlotViewerView::OnPreparePrinting(CPrintInfo* pInfo)
{
	// default preparation
	return DoPreparePrinting(pInfo);
}

void CDebugPlotViewerView::OnBeginPrinting(CDC* /*pDC*/, CPrintInfo* /*pInfo*/)
{
	// TODO: add extra initialization before printing
}

void CDebugPlotViewerView::OnEndPrinting(CDC* /*pDC*/, CPrintInfo* /*pInfo*/)
{
	// TODO: add cleanup after printing
}

void CDebugPlotViewerView::OnRButtonUp(UINT /* nFlags */, CPoint point)
{
	ClientToScreen(&point);
	OnContextMenu(this, point);
}

void CDebugPlotViewerView::OnContextMenu(CWnd* /* pWnd */, CPoint point)
{
#ifndef SHARED_HANDLERS
	theApp.GetContextMenuManager()->ShowPopupMenu(IDR_POPUP_EDIT, point.x, point.y, this, TRUE);
#endif
}

// CDebugPlotViewerView diagnostics

#ifdef _DEBUG
void CDebugPlotViewerView::AssertValid() const
{
	CView::AssertValid();
}

void CDebugPlotViewerView::Dump(CDumpContext& dc) const
{
	CView::Dump(dc);
}

CDebugPlotViewerDoc* CDebugPlotViewerView::GetDocument() const // non-debug version is inline
{
	ASSERT(m_pDocument->IsKindOf(RUNTIME_CLASS(CDebugPlotViewerDoc)));
	return (CDebugPlotViewerDoc*)m_pDocument;
}
#endif //_DEBUG

// CDebugPlotViewerView message handlers

int CDebugPlotViewerView::OnCreate(LPCREATESTRUCT lpcs)
{
	if (CView::OnCreate(lpcs) == -1)
		return -1;

	CRect rectDummy;
	rectDummy.SetRectEmpty();
	plotWndArea.CreateEx(0, NULL, L"PlotWndArea", WS_CHILD | WS_VISIBLE, rectDummy, this, 0, NULL);

	return 0;
}

void CDebugPlotViewerView::OnMouseMove(UINT nFlag, CPoint point)
{
	CView::OnMouseMove(nFlag, point);
}

void CDebugPlotViewerView::OnLButtonUp(UINT nFlags, CPoint point)
{
	CView::OnLButtonUp(nFlags, point);
}

LRESULT CDebugPlotViewerView::OnApp(WPARAM wParam, LPARAM lParam)
{
	switch (wParam)
	{
	case CMD_PLAY_PAUSE_ALL:
		{
			for (auto iter = plotWndArea.plotWndAreaProp->plotWndsInPlotWndAreaProp.begin();
				iter != plotWndArea.plotWndAreaProp->plotWndsInPlotWndAreaProp.end();
				iter++)
			{
				PlotWndProp * plotWndProp = *iter;
				plotWndProp->ForceUpdateGraph();
				if (plotWndProp->seriesInPlotWndProp.size() > 0)
				{
					DebuggingProcessProp * process = (DebuggingProcessProp *)lParam;
					if (plotWndProp->seriesInPlotWndProp[0]->GetProcess() == process)
						plotWndProp->PlayPauseProcess(!process->ReplayIsPaused());
				}
			}
			return 0;
		}
	case CMD_NEW_DOCUMENT:
		{
		this->plotWndArea.PostMessage(WM_APP, wParam, lParam);
		//this->GetDocument()->AddObserver(&this->plotWndArea);
		CDebugPlotViewerDoc * doc = (CDebugPlotViewerDoc *)lParam;
		plotWndArea.plotWndAreaProp = &doc->plotWndAreaProp;
		doc->plotWndAreaProp.targetWnd = &this->plotWndArea;
		return 0;
		}
	case CMD_GET_PLOT_WND_AREA_WND:
		{
		CWnd * wnd = &plotWndArea;
		CWnd ** ppWnd = (CWnd **)lParam;
		*ppWnd = &plotWndArea;
		return 0;
		}
	case CMD_UPDATE_GRAPH_TIMER:
		this->plotWndArea.plotWndAreaProp->PlotGraphToScreen();
		return 0;
	case CMD_RESET_VIEW:
		ResetView();
		return 0;
	case CMD_UPDATE_PLOT_WND:
		{
			vector<PlotWndProp *>::iterator iter;
			for (iter = plotWndArea.plotWndAreaProp->plotWndsInPlotWndAreaProp.begin();
				iter != plotWndArea.plotWndAreaProp->plotWndsInPlotWndAreaProp.end();
				iter++)
			{
				PlotWndProp * plotWndProp = *iter;
				plotWndProp->ForceUpdateGraph();
			}
		}
		return 0;
	case CMD_AUTO_LAYOUT:
		this->plotWndArea.PostMessage(WM_APP, wParam, lParam);
		return 0;
	default:
		return 0;
	}
}

void CDebugPlotViewerView::OnSize(UINT nType, int cx, int cy)
{
	CView::OnSize(nType, cx, cy);

	// TODO: Add your message handler code here
	CRect clientRect;
	GetClientRect(&clientRect);
	this->plotWndArea.MoveWindow(clientRect, 1);
}

void CDebugPlotViewerView::ResetView()
{
			std::vector<PlotWndProp *> plotWnds;

			std::vector<PlotWndProp *>::iterator iter;

			for (iter = this->plotWndArea.plotWndAreaProp->plotWndsInPlotWndAreaProp.begin();
				iter != this->plotWndArea.plotWndAreaProp->plotWndsInPlotWndAreaProp.end();
				iter++)
			{
				plotWnds.push_back(*iter);
			}

			for (iter = plotWnds.begin();
				iter != plotWnds.end();
				iter++)
			{
				(*iter)->targetWnd->SendMessage(WM_CLOSE, 0, 0);
			}

			ASSERT(this->plotWndArea.plotWndAreaProp->plotWndsInPlotWndAreaProp.size() == 0);
}


text:
This Docker image runs the [munki-trello](https://github.com/grahamgilbert/munki-trello) script. For more information about it's operation and on how to obtain the needed key and token, see the Readme for the original repository.

# Settings

Several options are customizable using environment variables.

* ``DOCKER_TRELLO_KEY``: The API Key
* ``DOCKER_TRELLO_TOKEN``: The Trello Application Token.
* ``DOCKER_TRELLO_BOARDID``: The Trello Board ID.
* ``DOCKER_TRELLO_TO_DEV_LIST``: The name of the 'To Development' list. Defaults to ``To Development``.
* ``DOCKER_TRELLO_DEV_LIST``: The name of the 'Development' list. Defaults to ``Development``.
* ``DOCKER_TRELLO_TO_TEST_LIST``: The name of the 'To Testing' list. Defaults to ``To Testing``.
* ``DOCKER_TRELLO_TEST_LIST``: The name of the 'Testing' list. Defaults to ``Testing``.
* ``DOCKER_TRELLO_TO_PROD_LIST``: The name of the 'To Production' list. Defaults to ``To Production``.
* ``DOCKER_TRELLO_MUNKI_PATH``: The path in the container to the Munki repository. Defaults to ``/munki_repo``.
* ``DOCKER_TRELLO_SUFFIX``:  Suffix for newly created 'Production' lists. Defaults to ``Production``.
* ``DOCKER_DEV_CATALOG``: Development Munki catalog. Defaults to ``development``.
* ``DOCKER_TEST_CATALOG`` Testing Munki catalog. Defaults to ``testing``.
* ``DOCKER_PROD_CATALOG``: Production Munki catalo. Defaults to ``production``.
* ``DOCKER_TRELLO_DATE_FORMAT``: Date format for Production lists. Defaults to ``%d/%m/%y``.
* ``DOCKER_TRELLO_AUTO_STAGE_TO_TEST``: Enable auto staging to test. Defaults to ``False``.
* ``DOCKER_TRELLO_AUTO_STAGE_TO_PROD``: Enable auto staging to production. Defaults to ``False``.
* ``DOCKER_TRELLO_DEV_STAGE_DAYS``: Days until autostaging from Development to Test. Defaults to ``0``.
* ``DOCKER_TRELLO_TEST_STAGE_DAYS``: Days until autostaging from Testing to Production. Defaults to ``0``.
* ``DOCKER_TRELLO_PRODUCTION_LIST`` Name of the Production list. Ignored if ``DOCKER_TRELLO_SUFFIX`` isn't set to an empty string.

#Running the container

It's recommended to run this container using the ``--rm`` option so the container is destroyed after the script has run.

```bash
$ docker pull pebbleit/munki-trello
$ docker run --rm \
  -v /var/www/munki:/munki_repo \
  -e DOCKER_TRELLO_KEY=yourapikey \
  -e DOCKER_TRELLO_TOKEN=yourtoken \
  -e DOCKER_TRELLO_BOARDID=abc123 \
  grahamgilbert/munki-trello
```


text:
extern crate serde;
extern crate serde_json;

#[macro_use]
extern crate serde_derive;

#[macro_use]
extern crate log;

pub mod server_info;
pub mod nats_client;
pub mod connect_option;


text:
layout: post
---

**In this Post, I have and will continue to collect the useful quotes I think, and write down here.**

---
## 05/09/2014

- provide us with more fine-grained control over the queries we can write.

## 05/16/2014

- viable 可行的
- lickety-split 极快的
- errand 差事
- nastier 下流的
- dissident 意见不同者
- distract 心烦

## 07/13/2014

- stand the test of time 经得起时间考验


text:
package jiguang.chat.utils.citychoose.view.myinterface;

import jiguang.chat.utils.citychoose.view.WheelView;

/**
 * Wheel scrolled listener interface.
 */
public interface OnWheelScrollListener {
	/**
	 * Callback method to be invoked when scrolling started.
	 * @param wheel the wheel view whose state has changed.
	 */
	void onScrollingStarted(WheelView wheel);

	/**
	 * Callback method to be invoked when scrolling ended.
	 * @param wheel the wheel view whose state has changed.
	 */
	void onScrollingFinished(WheelView wheel);
}


text:
type: post
title: XAP.NET MongoDB Data Grid
categories: SBP
parent: data-access-patterns.html
weight: 1310
---

|Author|XAP Version|Last Updated | Reference | Download |
|------|-----------|-------------|-----------|----------|
|Shay Hassidim| 9.7| April 2014| |           |          |

# Overview

The MongoDB Data-Grid example demonstrates a common Data Grid / Caching architecture using MongoDB for persistence. It includes the following components.

- A Client application that perform write and read operations against a remote clustered IMDG.
- A Clustered IMDG with write-behind (Mirror service) with pre-fetch (initial load) enabled. The Data grid using MongoDB database.

![image.jpeg](/attachment_files/mongodatagrid/mongodatagrid002.jpg)

This best practice will demonstrate show to implement this with XAP.NET.

# Structure

The example contains two .Net projects:

- `GigaSpaces.Examples.Datagrid.Commons`- Includes the entities project (`Person`) used in the example and other common functionalities.
- `GigaSpaces.Examples.Datagrid.Client` - A client application performs write and read operations against the data grid.

The example includes two additional Processing Unit folders:

- datagrid-mongo - Include a jar with the data grid configuration. See within the jar the `pu.xml` for MongoDB URL. `mongodb://localhost:27017/db` used by default.
- mirror-mongo - Include a jar with the mirror configuration. See the within the jar the `pu.xml` for MongoDB URL. `mongodb://localhost:27017/db` used by default.

# Prerequisites

- MongodbDB (win32-x86_64-2008plus-2.4.9) installed and running.
- Visual Studio 2010 with Service pack 1 or Visual Studio 2013
- XAP.NET 9.7 installed. Have the license key placed into `C:\GigaSpaces\XAP.NET 9.7.0 x64\Runtime\gslicense.xml`.

# Building the Example

Step 1:
[Download the example](/download_files/sbp/Datagrid-MongoDb.zip) and extract it into the `<GigaSpaces XAP .Net Root>\Examples` (i.e. `C:\GigaSpaces\XAP.NET 9.7.0 x64\NET v4.0.30319\Examples`) folder. A new folder called `Datagrid-MongoDb` will be created.

Step 2:
Browse to the `Datagrid-MongoDb` folder

Step 3:
Run the `BuildAll.bat` script to compile the example.

# Running the Data Grid

Step 1:
Run Gigaspaces Agent by running the StartAgent.bat script. This will start 3 containers.

Step 2:
Deploy the data grid and the Mirror service by running `DeployDataGrid.bat`. You should see this after running the `Gs-ui.exe`:

![image](/attachment_files/mongodatagrid/mongodatagrid004.jpg)

# Running the Client Application

The client application has several options:

1. `runWrite.bat` - will write 10 `Person` objects into the data grid and persist to MongoDB.
2. `runWriteMultiple.bat` - will write 100 `Person` objects (10 batches of 10 Person objects) into the data grid and persist to MongoDB.
3. `runRead.bat` - will read a `Person` object from the data grid.
4. `runReadMultiple.bat` - will read a 100 `Person` object from the data grid.

# Opening .NET Solution with Microsoft Visual Studio

1.  Double-click the `GigaSpaces.Examples.Datagrid.sln` file.
2.  Choose `Build > Build Solution` menu. The project files and dependencies are created and copied to the `release` directory.

# Viewing the data within the Data Grid

Run GigaSpaces UI: Go to `<GigaSpaces Root>\Bin` and run `Gs-ui.exe`. This will allow you to view the content of the data grid.

![image](/attachment_files/mongodatagrid/mongodatagrid006.jpg)

![image](/attachment_files/mongodatagrid/mongodatagrid008.jpg)

![image](/attachment_files/mongodatagrid/mongodatagrid010.jpg)

# Viewing data Persist into MongoDB

```bash
\mongodb-win32-x86_64-1.8.2\bin>mongo.exe
> use db
switched to db db
> db.GigaSpaces.Examples.Datagrid.Commons.Entities.Person.count()
50
> db.GigaSpaces.Examples.Datagrid.Commons.Entities.Person.find()
{ "__type__" : "GigaSpaces.Examples.Datagrid.Commons.Entities.Person", "FirstName" : "Name101", "Age" : "101", "LastName" : "lastname101", "_id" : "33
94b1f1-39d1-4c04-8c73-6f41d42c13ad" }
{ "__type__" : "GigaSpaces.Examples.Datagrid.Commons.Entities.Person", "FirstName" : "Name102", "Age" : "102", "LastName" : "lastname102", "_id" : "d6
a18590-ffb3-4dad-9548-009004b86353" }¦
```

## Setting MongoDB URL

To modify the `MongoDB URL` used with the example update the `pu.xml` within the `Datagrid-mongo.jar` and `mirror-mongo.jar` to have the right value instead the one used:

```xml
<constructor-arg value="mongodb://localhost:27017/db" type="java.lang.String" />
```

## Running Data Grid in Cache Miss Mode

To run the Data Grid in Cache miss mode update the `pu.xml` within the `Datagrid-mongo.jar` to have:

```xml
<os-core:embedded-space id="space" name="datagrid-mongo" space-data-source="mongospaceDataSource" mirror="true" schema="persistent">
  <os-core:properties>
    <props>
	    <!-- 0 for LRU , 1 for IN CACHE -->
		<prop key="space-config.engine.cache_policy">0</prop>

		<prop key="space-config.engine.initial_load">0</prop>
		<prop key="space-config.engine.cache_size">100000</prop>

		<prop key="space-config.engine.memory_usage.enabled">true</prop>
		<prop key="cluster-config.cache-loader.central-data-source">true</prop>
		<prop key="cluster-config.mirror-service.supports-partial-update">true</prop>
		<prop key="space-config.engine.memory_usage.high_watermark_percentage">90</prop>
		<prop key="space-config.engine.memory_usage.write_only_block_percentage">85</prop>
		<prop key="space-config.engine.memory_usage.write_only_check_percentage">76</prop>
		<prop key="space-config.engine.memory_usage.low_watermark_percentage">75</prop>
		<prop key="space-config.engine.memory_usage.eviction_batch_size">100</prop>
		<prop key="space-config.engine.memory_usage.retry_yield_time">2000</prop>
		<prop key="space-config.engine.memory_usage.retry_count">10</prop>
		<prop key="space-config.engine.memory_usage.explicit-gc">false</prop>
		<prop key="space-config.engine.memory_usage.gc-before-shortage">false</prop>

     </props>
  </os-core:properties>
</os-core:embedded-space>
```

The following controls how Cache miss works:

```xml
<prop key="space-config.engine.cache_size">10000</prop>
<prop key="space-config.engine.initial_load">0</prop>
```


text:
package com.itude.mobile.mobbl.core.services.datamanager.handlers;

import com.itude.mobile.mobbl.core.configuration.webservices.MBEndPointDefinition;
import com.itude.mobile.mobbl.core.configuration.webservices.MBWebservicesConfiguration;
import com.itude.mobile.mobbl.core.configuration.webservices.MBWebservicesConfigurationParser;
import com.itude.mobile.mobbl.core.model.MBDocument;
import com.itude.mobile.mobbl.core.services.MBResourceService;
import com.itude.mobile.mobbl.core.services.datamanager.MBDataHandlerBase;
import com.itude.mobile.mobbl.core.util.MBCacheManager;
import com.itude.mobile.web.exceptions.ItudeRuntimeException;

/**
 * Retrieves and sends MBDocument instances to and from a webservice.
 * <br/>
 * The MBWebserviceDataHandler is the top level in the DataHandlers for HTTP network communication.
 * Default behavior is to process an MBDocument, add the result to the request body and perform an HTTP operation (POST/GET).
 *
 * The endpoints.xml file maps Document names to Webservice URL's together with caching and timeout information.
 * The response body is parsed and validated against the Document Definition.
 *
 * The response can be handled by a ResultListener, also defined in the endpoints.xml file. Matching is by regex, so errors can be flexibly handled.
 *
 * Override this class to influence behavior. There are a bunch of template methods for easily changing HTTP headers, HTTP method etc.
 *
 * Caching is configurable and automatic. The cache key is based on the document name and arguments. For REST webservices the operation name is one of the arguments.
 */
public abstract class MBWebserviceDataHandler extends MBDataHandlerBase
{
  private final MBWebservicesConfiguration _webServiceConfiguration;
  private static final String              ENDPOINTS_NAME = "endpoints";

  public MBWebserviceDataHandler()
  {
    MBWebservicesConfigurationParser parser = new MBWebservicesConfigurationParser();
    byte[] data = MBResourceService.getInstance().getResourceByID(ENDPOINTS_NAME);
    _webServiceConfiguration = (MBWebservicesConfiguration) parser.parseData(data, ENDPOINTS_NAME);
  }

  @Override
  public MBDocument loadDocument(String documentName)
  {
    return loadDocument(documentName, null);
  }

  @Override
  public MBDocument loadDocument(String documentName, MBDocument doc)
  {
    MBEndPointDefinition endPoint = getEndPointForDocument(documentName);
    if (endPoint == null)
    {
      throw new ItudeRuntimeException("No endpoint for document " + documentName + " found");
    }
    boolean cacheable = endPoint.isCacheable();
    boolean globalCacheable = endPoint.isGlobalCacheable();
    String documentIdentifier = null;

    if (cacheable)
    {
      MBDocument result;

      documentIdentifier = doc == null ? documentName : documentName + doc.getUniqueId();
      result = MBCacheManager.documentForKey(documentIdentifier, globalCacheable);

      if (result != null)
      {
        return result;
      }
    }

    MBDocument result = doLoadDocument(documentName, doc);

    if (cacheable)
    {
      if (doc == null)
      {
        MBCacheManager.setDocument(result, documentIdentifier, endPoint.getTtl(), globalCacheable);
      }
      else
      {
        MBCacheManager.setDocument(result, documentIdentifier, endPoint.getTtl(), globalCacheable);
      }
    }

    return result;
  }

  protected abstract MBDocument doLoadDocument(String documentName, MBDocument doc);

  @Override
  public void storeDocument(MBDocument document)
  {
  }

  public MBEndPointDefinition getEndPointForDocument(String name)
  {
    return _webServiceConfiguration.getEndPointForDocumentName(name);
  }

}


text:
#pragma once
#include <vector>
#include <utility>
#include <unordered_map>
#include <string>
#include <algorithm>
#include "util/lp/lp_utils.h"
#include "util/lp/canonic_left_side.h"
namespace lean {
inline lconstraint_kind flip_kind(lconstraint_kind t) {
    return static_cast<lconstraint_kind>( - static_cast<int>(t));
}

inline std::string lconstraint_kind_string(lconstraint_kind t) {
    switch (t) {
    case LE: return std::string("<=");
    case LT: return std::string("<");
    case GE: return std::string(">=");
    case GT: return std::string(">");
    case EQ: return std::string("=");
    }
    lean_unreachable();
    return std::string(); // it is unreachable
}

class lar_base_constraint {
public:
    lconstraint_kind m_kind;
    mpq m_right_side;
    virtual buffer<std::pair<mpq, var_index>> get_left_side_coefficients() const = 0;
    constraint_index m_index; // the index of constraint
    lar_base_constraint() {}
    lar_base_constraint(lconstraint_kind kind, mpq right_side, constraint_index index) :m_kind(kind), m_right_side(right_side), m_index(index) {}

    virtual unsigned size() const = 0;
    virtual ~lar_base_constraint(){}
};

class lar_constraint : public lar_base_constraint {
public:
    std::unordered_map<var_index, mpq> m_left_side_map_from_index_to_coefficient;
    lar_constraint() {}
    lar_constraint(const buffer<std::pair<mpq, var_index>> & left_side, lconstraint_kind kind, mpq right_side, constraint_index index);

    lar_constraint(const lar_base_constraint & c);

    unsigned size() const {
        return static_cast<unsigned>(m_left_side_map_from_index_to_coefficient.size());
    }

    buffer<std::pair<mpq, var_index>> get_left_side_coefficients() const;
};

class lar_normalized_constraint : public lar_base_constraint {
public:
    canonic_left_side* m_canonic_left_side;
    mpq m_ratio_to_original; // by multiplying this constraint by m_ratio_to_original we get the original one
    lar_constraint m_origin_constraint;
    lar_normalized_constraint(canonic_left_side * ls, mpq ratio, lconstraint_kind kind, mpq right_side, const lar_constraint & origin):
        lar_base_constraint(kind, right_side, origin.m_index),
        m_canonic_left_side(ls),
        m_ratio_to_original(ratio),
        m_origin_constraint(origin) {
    }

    lar_normalized_constraint() {}

    buffer<std::pair<mpq, var_index>> get_left_side_coefficients() const;
    unsigned size() const {
        return m_canonic_left_side->size();
    }
};
}


text:
package com.sfcd.hidingappbar;

import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
import android.animation.ValueAnimator;
import android.content.Context;
import android.support.design.widget.AppBarLayout;
import android.support.design.widget.CoordinatorLayout;
import android.support.v4.view.MotionEventCompat;
import android.support.v4.view.ViewCompat;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;
import android.view.animation.DecelerateInterpolator;

public class HidingAppBarLayoutBehavior extends AppBarLayout.Behavior {
    View firstAppBarView;
    ValueAnimator mAnimator = null;

    public HidingAppBarLayoutBehavior(Context context, AttributeSet attrs) {
        super(context, attrs);
    }

    @Override
    public boolean onLayoutChild(CoordinatorLayout parent, AppBarLayout child, int layoutDirection) {
        boolean superLayout = super.onLayoutChild(parent, child, layoutDirection);

        this.firstAppBarView = child.getChildAt(0);

        return superLayout;
    }

    private void removeAnimator() {
        if (mAnimator != null) {
            mAnimator.cancel();
            mAnimator = null;
        }
    }

    private static int getStatusBarHeight(Context ctx) {
        int result = 0;
        int resourceId = ctx.getResources().getIdentifier("status_bar_height", "dimen", "android");
        if (resourceId > 0) {
            result = ctx.getResources().getDimensionPixelSize(resourceId);
        }
        return result;
    }

    private int getHiddenHeight() {
        int res = 0;
        if (ViewCompat.getFitsSystemWindows(firstAppBarView)) {
            res -= getStatusBarHeight(firstAppBarView.getContext());
        }

        res += firstAppBarView.getHeight();

        return res;
    }

    @Override
    public boolean onStartNestedScroll(CoordinatorLayout coordinatorLayout, AppBarLayout child, View directTargetChild, View target, int nestedScrollAxes) {
        boolean nestedScrollStarted = super.onStartNestedScroll(coordinatorLayout, child, directTargetChild, target, nestedScrollAxes);
        if (nestedScrollStarted) {
            removeAnimator();
        }
        return nestedScrollStarted;
    }

    @Override
    public void onStopNestedScroll(final CoordinatorLayout coordinatorLayout, AppBarLayout child, View target) {
        super.onStopNestedScroll(coordinatorLayout, child, target);
        onTouchEnded();
    }

    @Override
    public boolean onNestedFling(CoordinatorLayout coordinatorLayout, AppBarLayout child, View target, float velocityX, float velocityY, boolean consumed) {
        int offset = getTopAndBottomOffset();
        if (-offset < getHiddenHeight() && velocityY < 0 && !consumed) {
            return false;
        } else {
            return super.onNestedFling(coordinatorLayout, child, target, velocityX, velocityY, consumed);
        }
    }

    @Override
    public boolean onTouchEvent(CoordinatorLayout parent, AppBarLayout child, MotionEvent ev) {
        boolean clearAnim = false;
        switch (MotionEventCompat.getActionMasked(ev)) {
            case MotionEvent.ACTION_UP: {
                onTouchEnded();
                clearAnim = true;
            }
        }

        if(!clearAnim) {
            super.onTouchEvent(parent, child, ev);
        }

        return true;
    }

    private void onTouchEnded() {
        int offset = getTopAndBottomOffset();

        if (-offset < getHiddenHeight()) {
            if (mAnimator == null) {
                mAnimator = new ValueAnimator();
                mAnimator.setInterpolator(new DecelerateInterpolator());
                mAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
                    @Override
                    public void onAnimationUpdate(ValueAnimator animation) {
                        setTopAndBottomOffset((int) animation.getAnimatedValue());
                    }
                });
                mAnimator.addListener(new AnimatorListenerAdapter() {
                    @Override
                    public void onAnimationEnd(Animator animation) {
                        mAnimator = null;
                    }
                });
                mAnimator.setIntValues(offset, -getHiddenHeight());
                mAnimator.start();
            }

        }

    }
}


text:
/*
 * INET		An implementation of the TCP/IP protocol suite for the LINUX
 *		operating system.  INET is implemented using the  BSD Socket
 *		interface as the means of communication with the user level.
 *
 *		Definitions for inet_sock
 *
 * Authors:	Many, reorganised here by
 * 		Arnaldo Carvalho de Melo <acme@mandriva.com>
 *
 *		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.
 */
#ifndef _INET_SOCK_H
#define _INET_SOCK_H

#include <linux/kmemcheck.h>
#include <linux/string.h>
#include <linux/types.h>
#include <linux/jhash.h>
#include <linux/netdevice.h>

#include <net/flow.h>
#include <net/sock.h>
#include <net/request_sock.h>
#include <net/netns/hash.h>

/** struct ip_options - IP Options
 *
 * @faddr - Saved first hop address
 * @is_data - Options in __data, rather than skb
 * @is_strictroute - Strict source route
 * @srr_is_hit - Packet destination addr was our one
 * @is_changed - IP checksum more not valid
 * @rr_needaddr - Need to record addr of outgoing dev
 * @ts_needtime - Need to record timestamp
 * @ts_needaddr - Need to record addr of outgoing dev
 */
struct ip_options {
	__be32		faddr;
	unsigned char	optlen;
	unsigned char	srr;
	unsigned char	rr;
	unsigned char	ts;
	unsigned char	is_strictroute:1,
			srr_is_hit:1,
			is_changed:1,
			rr_needaddr:1,
			ts_needtime:1,
			ts_needaddr:1;
	unsigned char	router_alert;
	unsigned char	cipso;
	unsigned char	__pad2;
	unsigned char	__data[0];
};

struct ip_options_rcu {
	struct rcu_head rcu;
	struct ip_options opt;
};

struct ip_options_data {
	struct ip_options_rcu	opt;
	char			data[40];
};

struct inet_request_sock {
	struct request_sock	req;
#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
	u16			inet6_rsk_offset;
#endif
	__be16			loc_port;
	__be32			loc_addr;
	__be32			rmt_addr;
	__be16			rmt_port;
	kmemcheck_bitfield_begin(flags);
	u16			snd_wscale : 4,
				rcv_wscale : 4,
				tstamp_ok  : 1,
				sack_ok	   : 1,
				wscale_ok  : 1,
				ecn_ok	   : 1,
				acked	   : 1,
				no_srccheck: 1;
	kmemcheck_bitfield_end(flags);
	struct ip_options_rcu	*opt;
};

static inline struct inet_request_sock *inet_rsk(const struct request_sock *sk)
{
	return (struct inet_request_sock *)sk;
}

struct inet_cork {
	unsigned int		flags;
	__be32			addr;
	struct ip_options	*opt;
	unsigned int		fragsize;
	struct dst_entry	*dst;
	int			length; /* Total length of all frames */
	struct page		*page;
	u32			off;
	u8			tx_flags;
};

struct inet_cork_full {
	struct inet_cork	base;
	struct flowi		fl;
};

struct ip_mc_socklist;
struct ipv6_pinfo;
struct rtable;

/** struct inet_sock - representation of INET sockets
 *
 * @sk - ancestor class
 * @pinet6 - pointer to IPv6 control block
 * @inet_daddr - Foreign IPv4 addr
 * @inet_rcv_saddr - Bound local IPv4 addr
 * @inet_dport - Destination port
 * @inet_num - Local port
 * @inet_saddr - Sending source
 * @uc_ttl - Unicast TTL
 * @inet_sport - Source port
 * @inet_id - ID counter for DF pkts
 * @tos - TOS
 * @mc_ttl - Multicasting TTL
 * @is_icsk - is this an inet_connection_sock?
 * @mc_index - Multicast device index
 * @mc_list - Group array
 * @cork - info to build ip hdr on each ip frag while socket is corked
 */
struct inet_sock {
	/* sk and pinet6 has to be the first two members of inet_sock */
	struct sock		sk;
#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
	struct ipv6_pinfo	*pinet6;
#endif
	/* Socket demultiplex comparisons on incoming packets. */
#define inet_daddr		sk.__sk_common.skc_daddr
#define inet_rcv_saddr		sk.__sk_common.skc_rcv_saddr

	__be16			inet_dport;
	__u16			inet_num;
	__be32			inet_saddr;
	__s16			uc_ttl;
	__u16			cmsg_flags;
	__be16			inet_sport;
	__u16			inet_id;

	struct ip_options_rcu __rcu	*inet_opt;
	__u8			tos;
	__u8			min_ttl;
	__u8			mc_ttl;
	__u8			pmtudisc;
	__u8			recverr:1,
				is_icsk:1,
				freebind:1,
				hdrincl:1,
				mc_loop:1,
				transparent:1,
				mc_all:1,
				nodefrag:1;
	int			mc_index;
	__be32			mc_addr;
	struct ip_mc_socklist __rcu	*mc_list;
	struct inet_cork_full	cork;
};

#define IPCORK_OPT	1	/* ip-options has been held in ipcork.opt */
#define IPCORK_ALLFRAG	2	/* always fragment (for ipv6 for now) */

static inline struct inet_sock *inet_sk(const struct sock *sk)
{
	return (struct inet_sock *)sk;
}

static inline void __inet_sk_copy_descendant(struct sock *sk_to,
					     const struct sock *sk_from,
					     const int ancestor_size)
{
	memcpy(inet_sk(sk_to) + 1, inet_sk(sk_from) + 1,
	       sk_from->sk_prot->obj_size - ancestor_size);
}
#if !(defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE))
static inline void inet_sk_copy_descendant(struct sock *sk_to,
					   const struct sock *sk_from)
{
	__inet_sk_copy_descendant(sk_to, sk_from, sizeof(struct inet_sock));
}
#endif

extern int inet_sk_rebuild_header(struct sock *sk);

extern u32 inet_ehash_secret;
extern void build_ehash_secret(void);

static inline unsigned int inet_ehashfn(struct net *net,
					const __be32 laddr, const __u16 lport,
					const __be32 faddr, const __be16 fport)
{
	return jhash_3words((__force __u32) laddr,
			    (__force __u32) faddr,
			    ((__u32) lport) << 16 | (__force __u32)fport,
			    inet_ehash_secret + net_hash_mix(net));
}

static inline int inet_sk_ehashfn(const struct sock *sk)
{
	const struct inet_sock *inet = inet_sk(sk);
	const __be32 laddr = inet->inet_rcv_saddr;
	const __u16 lport = inet->inet_num;
	const __be32 faddr = inet->inet_daddr;
	const __be16 fport = inet->inet_dport;
	struct net *net = sock_net(sk);

	return inet_ehashfn(net, laddr, lport, faddr, fport);
}

static inline struct request_sock *inet_reqsk_alloc(struct request_sock_ops *ops)
{
	struct request_sock *req = reqsk_alloc(ops);
	struct inet_request_sock *ireq = inet_rsk(req);

	if (req != NULL) {
		kmemcheck_annotate_bitfield(ireq, flags);
		ireq->opt = NULL;
	}

	return req;
}

static inline __u8 inet_sk_flowi_flags(const struct sock *sk)
{
	__u8 flags = 0;

	if (inet_sk(sk)->transparent || inet_sk(sk)->hdrincl)
		flags |= FLOWI_FLAG_ANYSRC;
	if (sk->sk_protocol == IPPROTO_TCP)
		flags |= FLOWI_FLAG_PRECOW_METRICS;
	return flags;
}

#endif	/* _INET_SOCK_H */


text:
<!--
Pro-tip: You can leave this block commented, and it still works!

Select the appropriate areas for your issue:

/area API
/area monitoring
/area networking
/area test-and-release

Classify what kind of issue this is:

/kind question
/kind bug
/kind cleanup
/kind doc
/kind feature
/kind good-first-issue

-->

## Expected Behavior

## Actual Behavior

## Steps to Reproduce the Problem

1.
2.
3.

## Additional Info