/*
 * Copyright © 2017 Intel Corporation
 *
 * Permission is hereby granted, free of charge, to any person obtaining a
 * copy of this software and associated documentation files (the
 * "Software"), to deal in the Software without restriction, including
 * without limitation the rights to use, copy, modify, merge, publish,
 * distribute, sub license, and/or sell copies of the Software, and to
 * permit persons to whom the Software is furnished to do so, subject to
 * the following conditions:
 *
 * The above copyright notice and this permission notice (including the
 * next paragraph) shall be included in all copies or substantial portions
 * of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
 * IN NO EVENT SHALL PRECISION INSIGHT AND/OR ITS SUPPLIERS BE LIABLE FOR
 * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
 * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
 * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 *
 * Authors:
 *    Peng Chen <peng.c.chen@intel.com>
 *
 */

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>
#include <assert.h>

#include "intel_driver.h"
#include "intel_batchbuffer.h"
#include "i965_defines.h"
#include "i965_drv_video.h"
#include "i965_encoder.h"
#include "i965_encoder_common.h"
#include "i965_encoder_utils.h"
#include "i965_encoder_api.h"
#include "gen10_hcp_common.h"
#include "gen10_hevc_enc_common.h"

static const unsigned char default_scaling16[16] = {
    16, 16, 16, 16,
    16, 16, 16, 16,
    16, 16, 16, 16,
    16, 16, 16, 16
};

static const unsigned char default_scaling_intra[64] = {
    16, 16, 16, 16, 17, 18, 21, 24,
    16, 16, 16, 16, 17, 19, 22, 25,
    16, 16, 17, 18, 20, 22, 25, 29,
    16, 16, 18, 21, 24, 27, 31, 36,
    17, 17, 20, 24, 30, 35, 41, 47,
    18, 19, 22, 27, 35, 44, 54, 65,
    21, 22, 25, 31, 41, 54, 70, 88,
    24, 25, 29, 36, 47, 65, 88, 115
};

static const unsigned char default_scaling_inter[64] = {
    16, 16, 16, 16, 17, 18, 20, 24,
    16, 16, 16, 17, 18, 20, 24, 25,
    16, 16, 17, 18, 20, 24, 25, 28,
    16, 17, 18, 20, 24, 25, 28, 33,
    17, 18, 20, 24, 25, 28, 33, 41,
    18, 20, 24, 25, 28, 33, 41, 54,
    20, 24, 25, 28, 33, 41, 54, 71,
    24, 25, 28, 33, 41, 54, 71, 91
};

static void
hevc_init_qm_matrix(struct gen10_hevc_enc_frame_info *frame_info,
                    VAQMatrixBufferHEVC *qm_matrix,
                    int matrix_flag)
{
    uint8_t *real_qm, real_dc_qm = 0;
    uint16_t *real_fqm, *real_dc_fqm;
    int comps, len;
    int i, j, m, n;

    if (matrix_flag == 0) {
        for (m = 0; m < 4; m++) {
            comps = (m == 3) ? 1 : 3;
            len = (m == 0) ? 16 : 64;

            for (i = 0; i < comps; i++) {
                for (j = 0; j < 2; j++) {
                    real_qm = frame_info->qm_matrix[m][i][j];

                    switch (m) {
                    case 0:
                        memcpy(real_qm, qm_matrix->scaling_lists_4x4[i][j], len);
                        break;
                    case 1:
                        memcpy(real_qm, qm_matrix->scaling_lists_8x8[i][j], len);
                        break;
                    case 2:
                        memcpy(real_qm, qm_matrix->scaling_lists_16x16[i][j], len);

                        real_dc_qm = qm_matrix->scaling_list_dc_16x16[i][j];
                        frame_info->qm_dc_matrix[0][i][j] = real_dc_qm;
                        break;
                    case 3:
                        memcpy(real_qm, qm_matrix->scaling_lists_32x32[j], len);

                        real_dc_qm = qm_matrix->scaling_list_dc_32x32[j];
                        frame_info->qm_dc_matrix[1][i][j] = real_dc_qm;
                        break;
                    default:
                        assert(0);
                    }

                    if (i == 0) {
                        real_fqm = frame_info->fqm_matrix[m][j];

                        for (n = 0; n < len; n++) {
                            uint32_t qm_value = *(real_qm + n);
                            uint32_t fqm_value = 0;

                            fqm_value = (qm_value < 2) ? 0xFFFF : 0xFFFF / qm_value;

                            *(real_fqm + n) = fqm_value;
                        }

                        if (m == 2 || m == 3) {
                            uint32_t dc = real_dc_qm;

                            real_dc_fqm = &frame_info->fqm_dc_matrix[m - 2][j];
                            dc = (dc < 2) ? 0xFFFF : 0xFFFF / dc;

                            *real_dc_fqm = dc;
                        }
                    }
                }
            }
        }
    } else if (matrix_flag == 1) {
        for (m = 0; m < 4; m++) {
            comps = (m == 3) ? 1 : 3;
            len = (m == 0) ? 16 : 64;

            for (i = 0; i < comps; i++) {
                for (j = 0; j < 2; j++) {
                    real_qm = frame_info->qm_matrix[m][i][j];

                    switch (m) {
                    case 0:
                        memcpy(real_qm, default_scaling16, len);
                        break;
                    case 1:
                    case 2:
                    case 3:
                        if (j == 0)
                            memcpy(real_qm, default_scaling_intra, len);
                        else
                            memcpy(real_qm, default_scaling_inter, len);

                        break;
                    default:
                        assert(0);
                    }

                    if (i == 0) {
                        real_fqm = frame_info->fqm_matrix[m][j];

                        for (n = 0; n < len; n++) {
                            uint32_t qm_value = *(real_qm + n);
                            uint32_t fqm_value = 0;

                            fqm_value = (qm_value < 2) ? 0xFFFF : 0xFFFF / qm_value;

                            *(real_fqm + n) = fqm_value;
                        }
                    }
                }
            }
        }

        memset(&frame_info->qm_dc_matrix, 16, sizeof(frame_info->qm_dc_matrix));

        for (i = 0; i < 2; i++) {
            for (j = 0; j < 2; j++)
                frame_info->fqm_dc_matrix[i][j] = 0x1000;
        }

    } else if (matrix_flag == 2) {
        memset(&frame_info->qm_matrix, 16, sizeof(frame_info->qm_matrix));
        memset(&frame_info->qm_dc_matrix, 16, sizeof(frame_info->qm_dc_matrix));

        for (m = 0; m < 4; m++) {
            for (j = 0; j < 2; j++) {
                for (n = 0; n < 64; n++)
                    frame_info->fqm_matrix[m][j][n] = 0x1000;
            }
        }

        for (i = 0; i < 2; i++) {
            for (j = 0; j < 2; j++)
                frame_info->fqm_dc_matrix[i][j] = 0x1000;
        }
    } else
        assert(0);
}

static int
hevc_enc_map_pic_index(VASurfaceID id,
                       VAPictureHEVC *pic_list,
                       int pic_list_count)
{
    int i;

    if (id != VA_INVALID_ID) {
        for (i = 0; i < pic_list_count; i++) {
            VAPictureHEVC * const va_pic = &pic_list[i];

            if (va_pic->picture_id == id &&
                !(va_pic->flags & VA_PICTURE_HEVC_INVALID))
                return i;
        }
    }

    return -1;
}

static int
gen10_hevc_enc_get_relocation_flag(VAEncSequenceParameterBufferHEVC *cur_seq_param,
                                   VAEncSequenceParameterBufferHEVC *last_seq_param)
{
    if ((cur_seq_param->seq_fields.bits.bit_depth_luma_minus8 !=
         last_seq_param->seq_fields.bits.bit_depth_luma_minus8) ||
        (cur_seq_param->seq_fields.bits.bit_depth_chroma_minus8 !=
         last_seq_param->seq_fields.bits.bit_depth_chroma_minus8) ||
        (cur_seq_param->log2_min_luma_coding_block_size_minus3 !=
         last_seq_param->log2_min_luma_coding_block_size_minus3) ||
        (cur_seq_param->log2_diff_max_min_luma_coding_block_size !=
         last_seq_param->log2_diff_max_min_luma_coding_block_size) ||
        (cur_seq_param->pic_width_in_luma_samples !=
         last_seq_param->pic_width_in_luma_samples) ||
        (cur_seq_param->pic_height_in_luma_samples !=
         last_seq_param->pic_height_in_luma_samples) ||
        (cur_seq_param->seq_fields.bits.bit_depth_chroma_minus8 !=
         last_seq_param->seq_fields.bits.bit_depth_chroma_minus8) ||
        (cur_seq_param->seq_fields.bits.bit_depth_chroma_minus8 !=
         last_seq_param->seq_fields.bits.bit_depth_chroma_minus8))
        return 1;

    return 0;
}

void
gen10_hevc_enc_init_frame_info(VADriverContextP ctx,
                               struct encode_state *encode_state,
                               struct intel_encoder_context *encoder_context,
                               struct gen10_hevc_enc_frame_info *frame_info)
{
    uint32_t log2_max_coding_block_size = 0, raw_ctu_bits = 0;
    VAEncPictureParameterBufferHEVC *pic_param = NULL;
    VAEncSequenceParameterBufferHEVC *seq_param = NULL;
    VAEncSliceParameterBufferHEVC *slice_param = NULL;
    int i, j;

    pic_param = (VAEncPictureParameterBufferHEVC *)encode_state->pic_param_ext->buffer;
    seq_param = (VAEncSequenceParameterBufferHEVC *)encode_state->seq_param_ext->buffer;
    slice_param = (VAEncSliceParameterBufferHEVC *)encode_state->slice_params_ext[0]->buffer;

    frame_info->bit_depth_luma_minus8 = seq_param->seq_fields.bits.bit_depth_luma_minus8;
    frame_info->bit_depth_chroma_minus8 = seq_param->seq_fields.bits.bit_depth_chroma_minus8;
    frame_info->cu_size = 1 << (seq_param->log2_min_luma_coding_block_size_minus3 + 3);
    frame_info->lcu_size = 1 << (seq_param->log2_diff_max_min_luma_coding_block_size +
                                 seq_param->log2_min_luma_coding_block_size_minus3 + 3);
    frame_info->frame_width = (seq_param->pic_width_in_luma_samples / frame_info->cu_size) * frame_info->cu_size;
    frame_info->frame_height = (seq_param->pic_height_in_luma_samples / frame_info->cu_size) * frame_info->cu_size;
    frame_info->width_in_lcu  = ALIGN(frame_info->frame_width, frame_info->lcu_size) / frame_info->lcu_size;
    frame_info->height_in_lcu = ALIGN(frame_info->frame_height, frame_info->lcu_size) / frame_info->lcu_size;
    frame_info->width_in_cu  = ALIGN(frame_info->frame_width, frame_info->cu_size) / frame_info->cu_size;
    frame_info->height_in_cu = ALIGN(frame_info->frame_height, frame_info->cu_size) / frame_info->cu_size;
    frame_info->width_in_mb  = ALIGN(frame_info->frame_width, 16) / 16;
    frame_info->height_in_mb = ALIGN(frame_info->frame_height, 16) / 16;

    frame_info->picture_coding_type = slice_param->slice_type;

    frame_info->ctu_max_bitsize_allowed = pic_param->ctu_max_bitsize_allowed;

    log2_max_coding_block_size  = seq_param->log2_min_luma_coding_block_size_minus3 + 3 +
                                  seq_param->log2_diff_max_min_luma_coding_block_size;
    raw_ctu_bits = (1 << (2 * log2_max_coding_block_size + 3)) +
                   (1 << (2 * log2_max_coding_block_size + 2));
    raw_ctu_bits = (5 * raw_ctu_bits / 3);

    if (frame_info->ctu_max_bitsize_allowed == 0 ||
        frame_info->ctu_max_bitsize_allowed > raw_ctu_bits)
        frame_info->ctu_max_bitsize_allowed = raw_ctu_bits;

    frame_info->low_delay = 1;
    frame_info->arbitrary_num_mb_in_slice = 0;

    for (i = 0; i < encode_state->num_slice_params_ext; i++) {
        slice_param = (VAEncSliceParameterBufferHEVC *)encode_state->slice_params_ext[i]->buffer;

        if (i == 0) {
            frame_info->is_same_ref_list = 1;
            if (slice_param->slice_type == HEVC_SLICE_B) {
                if (slice_param->num_ref_idx_l0_active_minus1 >=
                    slice_param->num_ref_idx_l1_active_minus1) {
                    for (j = 0; j < slice_param->num_ref_idx_l1_active_minus1 + 1; j++)
                        if (slice_param->ref_pic_list0[j].picture_id !=
                            slice_param->ref_pic_list1[j].picture_id) {
                            frame_info->is_same_ref_list = 0;
                            break;
                        }
                } else
                    frame_info->is_same_ref_list = 0;
            }
        }

        if (slice_param->slice_type == HEVC_SLICE_B && frame_info->low_delay) {
            for (j = 0; j <= slice_param->num_ref_idx_l0_active_minus1; j++) {
                if (pic_param->decoded_curr_pic.pic_order_cnt <
                    slice_param->ref_pic_list0[j].pic_order_cnt)
                    frame_info->low_delay = 0;
            }

            for (j = 0; j <= slice_param->num_ref_idx_l1_active_minus1; j++) {
                if (pic_param->decoded_curr_pic.pic_order_cnt <
                    slice_param->ref_pic_list1[j].pic_order_cnt)
                    frame_info->low_delay = 0;
            }
        }

        if (!frame_info->arbitrary_num_mb_in_slice &&
            (slice_param->num_ctu_in_slice % frame_info->width_in_lcu))
            frame_info->arbitrary_num_mb_in_slice = 1;
    }

    for (i = 0; i < 8; i++) {
        frame_info->mapped_ref_idx_list0[i] = -1;
        frame_info->mapped_ref_idx_list1[i] = -1;
    }

    if (slice_param->slice_type != HEVC_SLICE_I) {
        for (i = 0; i <= slice_param->num_ref_idx_l0_active_minus1; i++)
            frame_info->mapped_ref_idx_list0[i] = hevc_enc_map_pic_index(slice_param->ref_pic_list0[i].picture_id,
                                                                         pic_param->reference_frames, 8);

        if (slice_param->slice_type == HEVC_SLICE_B) {
            for (i = 0; i <= slice_param->num_ref_idx_l1_active_minus1; i++)
                frame_info->mapped_ref_idx_list1[i] = hevc_enc_map_pic_index(slice_param->ref_pic_list1[i].picture_id,
                                                                             pic_param->reference_frames, 8);
        }
    }

    frame_info->slice_qp = pic_param->pic_init_qp + slice_param->slice_qp_delta;

    if (encoder_context->is_new_sequence ||
        memcmp(&frame_info->last_seq_param, seq_param, sizeof(*seq_param))) {
        VAQMatrixBufferHEVC *input_matrix = NULL;
        int matrix_flag = 0;

        if (seq_param->seq_fields.bits.scaling_list_enabled_flag) {
            if (pic_param->pic_fields.bits.scaling_list_data_present_flag) {
                if (encode_state->q_matrix && encode_state->q_matrix->buffer)
                    input_matrix = (VAQMatrixBufferHEVC *)encode_state->q_matrix->buffer;
                else if (encode_state->iq_matrix && encode_state->iq_matrix->buffer)
                    input_matrix = (VAQMatrixBufferHEVC *)encode_state->iq_matrix->buffer;

                matrix_flag = 0;
            } else
                matrix_flag = 1;
        } else
            matrix_flag = 2;

        hevc_init_qm_matrix(frame_info, input_matrix, matrix_flag);

        frame_info->gop_size = seq_param->intra_period;
        frame_info->gop_ref_dist = seq_param->ip_period;
        frame_info->gop_num_p = encoder_context->brc.num_pframes_in_gop;
        frame_info->gop_num_b[0] = encoder_context->brc.num_bframes_in_gop;
        frame_info->gop_num_b[1] = 0;
        frame_info->gop_num_b[2] = 0;

        if (gen10_hevc_enc_get_relocation_flag(seq_param,
                                               &frame_info->last_seq_param))
            frame_info->reallocate_flag = 1;
        else
            frame_info->reallocate_flag = 0;

        memcpy(&frame_info->last_seq_param, seq_param, sizeof(*seq_param));
    } else
        frame_info->reallocate_flag = 0;
}

static int
hevc_find_skipemulcnt(uint8_t *buf, int bits_length)
{
    int skip_cnt = 0, i = 0;

    if ((bits_length >> 3) < 6)
        return 0;

    for (i = 0; i < 3; i++)
        if (buf[i] != 0)
            break;

    if (i > 1) {
        if (buf[i] == 1)
            skip_cnt = i + 3;
    }

    return skip_cnt;
}

static void
gen10_hevc_enc_insert_object(VADriverContextP ctx,
                             struct intel_batchbuffer *batch,
                             uint8_t *header_data,
                             int length_in_bits,
                             int end_of_slice_flag,
                             int last_header_flag,
                             int emulation_flag,
                             int skip_emulation_bytes)
{
    gen10_hcp_pak_insert_object_param insert_param;

    memset(&insert_param, 0, sizeof(insert_param));

    insert_param.dw1.bits.end_of_slice_flag = end_of_slice_flag;
    insert_param.dw1.bits.last_header_flag = last_header_flag;
    insert_param.dw1.bits.emulation_flag = emulation_flag;

    if (emulation_flag) {
        if (skip_emulation_bytes)
            insert_param.dw1.bits.skip_emulation_bytes = skip_emulation_bytes;
        else
            insert_param.dw1.bits.skip_emulation_bytes = hevc_find_skipemulcnt((uint8_t *)header_data,
                                                                               length_in_bits);
    }

    insert_param.dw1.bits.data_bits_in_last_dw = length_in_bits & 0x1f;
    if (insert_param.dw1.bits.data_bits_in_last_dw == 0)
        insert_param.dw1.bits.data_bits_in_last_dw = 32;

    insert_param.inline_payload_ptr = header_data;
    insert_param.inline_payload_bits = length_in_bits;

    gen10_hcp_pak_insert_object(ctx, batch, &insert_param);
}

void
gen10_hevc_enc_insert_packed_header(VADriverContextP ctx,
                                    struct encode_state *encode_state,
                                    struct intel_encoder_context *encoder_context,
                                    struct intel_batchbuffer *batch)
{
    VAEncPackedHeaderParameterBuffer *param = NULL;
    uint8_t *header_data = NULL;
    uint32_t length_in_bits = 0;
    int packed_type = 0;
    int idx = 0, idx_offset = 0;
    int i = 0;

    for (i = 0; i < 4; i++) {
        idx_offset = 0;
        switch (i) {
        case 0:
            packed_type = VAEncPackedHeaderHEVC_VPS;
            break;
        case 1:
            packed_type = VAEncPackedHeaderHEVC_VPS;
            idx_offset = 1;
            break;
        case 2:
            packed_type = VAEncPackedHeaderHEVC_PPS;
            break;
        case 3:
            packed_type = VAEncPackedHeaderHEVC_SEI;
            break;
        default:
            break;
        }

        idx = va_enc_packed_type_to_idx(packed_type) + idx_offset;
        if (encode_state->packed_header_data[idx]) {
            param = (VAEncPackedHeaderParameterBuffer *)encode_state->packed_header_param[idx]->buffer;
            header_data = (uint8_t *)encode_state->packed_header_data[idx]->buffer;
            length_in_bits = param->bit_length;

            gen10_hevc_enc_insert_object(ctx, batch, header_data, length_in_bits,
                                         0, 0, !param->has_emulation_bytes, 0);
        }
    }
}

void
gen10_hevc_enc_insert_slice_header(VADriverContextP ctx,
                                   struct encode_state *encode_state,
                                   struct intel_encoder_context *encoder_context,
                                   struct intel_batchbuffer *batch,
                                   int slice_index)
{
    VAEncPackedHeaderParameterBuffer *param = NULL;
    uint8_t *header_data = NULL;
    uint32_t length_in_bits = 0;
    int count = 0, start_index = -1;
    int i = 0;

    count = encode_state->slice_rawdata_count[slice_index];
    start_index = encode_state->slice_rawdata_index[slice_index] &
                  SLICE_PACKED_DATA_INDEX_MASK;

    for (i = 0; i < count; i++) {
        param = (VAEncPackedHeaderParameterBuffer *)
                (encode_state->packed_header_params_ext[start_index + i]->buffer);

        if (param->type == VAEncPackedHeaderSlice)
            continue;

        header_data = (uint8_t *)encode_state->packed_header_data_ext[start_index]->buffer;
        length_in_bits = param->bit_length;

        gen10_hevc_enc_insert_object(ctx, batch, header_data, length_in_bits,
                                     0, 0, !param->has_emulation_bytes, 0);
    }

    start_index = -1;
    if (encode_state->slice_header_index[slice_index] & SLICE_PACKED_DATA_INDEX_TYPE)
        start_index = encode_state->slice_header_index[slice_index] &
                      SLICE_PACKED_DATA_INDEX_MASK;

    if (start_index == -1) {
        VAEncSequenceParameterBufferHEVC *seq_param = (VAEncSequenceParameterBufferHEVC *)encode_state->seq_param_ext->buffer;
        VAEncPictureParameterBufferHEVC *pic_param = (VAEncPictureParameterBufferHEVC *)encode_state->pic_param_ext->buffer;
        VAEncSliceParameterBufferHEVC *slice_param = (VAEncSliceParameterBufferHEVC *)encode_state->slice_params_ext[slice_index]->buffer;
        unsigned char *slice_header = NULL;
        int slice_header_bits = 0;

        slice_header_bits = build_hevc_slice_header(seq_param,
                                                    pic_param,
                                                    slice_param,
                                                    &slice_header,
                                                    0);

        gen10_hevc_enc_insert_object(ctx, batch, slice_header, slice_header_bits,
                                     0, 1, 1, 5);

        free(slice_header);
    } else {
        param = (VAEncPackedHeaderParameterBuffer *)
                (encode_state->packed_header_params_ext[start_index]->buffer);
        header_data = (uint8_t *)encode_state->packed_header_data_ext[start_index]->buffer;
        length_in_bits = param->bit_length;

        gen10_hevc_enc_insert_object(ctx, batch, header_data, length_in_bits,
                                     0, 1, !param->has_emulation_bytes, 0);
    }
}

#define ALLOC_GPE_RESOURCE(RES, NAME, SIZE)                 \
    do{                                                     \
        i965_free_gpe_resource(&common_res->RES);           \
        if (!i965_allocate_gpe_resource(i965->intel.bufmgr, \
                                 &common_res->RES,          \
                                 SIZE,                      \
                                 NAME))                     \
            goto FAIL;                                      \
    } while(0);

#define ALLOC_GPE_2D_RESOURCE(RES, NAME, W, H, P)               \
    do{                                                         \
        i965_free_gpe_resource(&priv_ctx->RES);                 \
        if (!i965_gpe_allocate_2d_resource(i965->intel.bufmgr,  \
                                 &common_res->RES,              \
                                 (ALIGN(W, 64)), H,             \
                                 (ALIGN(P, 64)),                \
                                 NAME))                         \
            goto FAIL;                                          \
    } while(0);

int
gen10_hevc_enc_init_common_resource(VADriverContextP ctx,
                                    struct encode_state *encode_state,
                                    struct intel_encoder_context *encoder_context,
                                    struct gen10_hevc_enc_common_res *common_res,
                                    struct gen10_hevc_enc_frame_info *frame_info,
                                    int inter_enabled,
                                    int vdenc_enabled)
{
    struct i965_driver_data *i965 = i965_driver_data(ctx);
    VAEncPictureParameterBufferHEVC *pic_param = NULL;
    struct object_surface *obj_surface;
    struct object_buffer *obj_buffer;
    int res_size = 0, size_shift = 0;
    int width = 0, height = 0;
    int i = 0;

    pic_param = (VAEncPictureParameterBufferHEVC *)encode_state->pic_param_ext->buffer;

    obj_buffer = encode_state->coded_buf_object;
    i965_free_gpe_resource(&common_res->compressed_bitstream.gpe_res);
    i965_dri_object_to_buffer_gpe_resource(&common_res->compressed_bitstream.gpe_res,
                                           obj_buffer->buffer_store->bo);
    common_res->compressed_bitstream.offset = I965_CODEDBUFFER_HEADER_SIZE;
    common_res->compressed_bitstream.end_offset = ALIGN(obj_buffer->size_element - 0x1000,
                                                        0x1000);

    i965_free_gpe_resource(&common_res->uncompressed_pic.gpe_res);
    i965_object_surface_to_2d_gpe_resource(&common_res->uncompressed_pic.gpe_res,
                                           encode_state->input_yuv_object);
    common_res->uncompressed_pic.obj_surface = encode_state->input_yuv_object;
    common_res->uncompressed_pic.surface_id = encoder_context->input_yuv_surface;

    i965_free_gpe_resource(&common_res->reconstructed_pic.gpe_res);
    i965_object_surface_to_2d_gpe_resource(&common_res->reconstructed_pic.gpe_res,
                                           encode_state->reconstructed_object);
    common_res->reconstructed_pic.obj_surface = encode_state->reconstructed_object;
    common_res->reconstructed_pic.surface_id = pic_param->decoded_curr_pic.picture_id;

    if (inter_enabled) {
        for (i = 0; i < 15; i++) {
            if (common_res->reference_pics[i].surface_id != VA_INVALID_ID)
                i965_free_gpe_resource(&common_res->reference_pics[i].gpe_res);

            obj_surface = encode_state->reference_objects[i];
            if (obj_surface && obj_surface->bo) {
                i965_object_surface_to_2d_gpe_resource(&common_res->reference_pics[i].gpe_res,
                                                       obj_surface);

                common_res->reference_pics[i].obj_surface = obj_surface;
                common_res->reference_pics[i].surface_id = pic_param->reference_frames[i].picture_id;
            } else {
                common_res->reference_pics[i].obj_surface = NULL;
                common_res->reference_pics[i].surface_id = VA_INVALID_ID;
            }
        }
    }

    if (frame_info->reallocate_flag) {
        width = frame_info->frame_width;
        height = frame_info->frame_height;
        size_shift = (frame_info->bit_depth_luma_minus8 ||
                      frame_info->bit_depth_chroma_minus8) ? 2 : 3;

        res_size = ALIGN(width, 32) << (6 - size_shift);
        ALLOC_GPE_RESOURCE(deblocking_filter_line_buffer,
                           "Deblocking filter line buffer",
                           res_size);
        ALLOC_GPE_RESOURCE(deblocking_filter_tile_line_buffer,
                           "Deblocking filter tile line buffer",
                           res_size);

        res_size = ALIGN(height +
                         frame_info->width_in_lcu * 6, 32) << (6 - size_shift);
        ALLOC_GPE_RESOURCE(deblocking_filter_tile_column_buffer,
                           "Deblocking filter tile column buffer",
                           res_size);

        res_size = (((width + 15) >> 4) * 188 +
                    frame_info->width_in_lcu * 9 + 1023) >> 3;
        ALLOC_GPE_RESOURCE(metadata_line_buffer,
                           "metadata line buffer",
                           res_size);

        res_size = (((width + 15) >> 4) * 172 +
                    frame_info->width_in_lcu * 9 + 1023) >> 3;
        ALLOC_GPE_RESOURCE(metadata_tile_line_buffer,
                           "metadata tile line buffer",
                           res_size);

        res_size = (((height + 15) >> 4) * 176 +
                    frame_info->height_in_lcu * 9 + 1023) >> 3;
        ALLOC_GPE_RESOURCE(metadata_tile_column_buffer,
                           "metadata tile column buffer",
                           res_size);

        res_size = ALIGN(((width >> 1) +
                          frame_info->width_in_lcu * 3), 16) << (6 - size_shift);
        ALLOC_GPE_RESOURCE(sao_line_buffer,
                           "sao line buffer",
                           res_size);

        res_size = ALIGN(((width >> 1) +
                          frame_info->width_in_lcu * 6), 16) << (6 - size_shift);
        ALLOC_GPE_RESOURCE(sao_tile_line_buffer,
                           "sao tile line buffer",
                           res_size);

        res_size = ALIGN(((height >> 1) +
                          frame_info->height_in_lcu * 6), 16) << (6 - size_shift);
        ALLOC_GPE_RESOURCE(sao_tile_column_buffer,
                           "sao tile column buffer",
                           res_size);

        if (vdenc_enabled) {
            res_size = 0x500000;
            ALLOC_GPE_RESOURCE(streamout_data_destination_buffer,
                               "streamout data destination buffer",
                               res_size);
        }

        res_size = I965_MAX_NUM_SLICE * 64;
        ALLOC_GPE_RESOURCE(picture_status_buffer,
                           "picture status buffer",
                           res_size);

        res_size = frame_info->width_in_lcu * frame_info->height_in_lcu * 256;
        ALLOC_GPE_RESOURCE(ildb_streamout_buffer,
                           "ildb streamout buffer",
                           res_size);

        //res_size = frame_info->width_in_lcu * frame_info->height_in_lcu * 16;
        width = ALIGN(frame_info->frame_width, 64) >> 3;
        height = ALIGN(frame_info->frame_height, 64) >> 3;
        res_size = width * height * 16 + 1024;
        ALLOC_GPE_RESOURCE(sao_streamout_data_destination_buffer,
                           "sao streamout date destination buffer",
                           res_size);

        res_size = ALIGN(8 * 64, 4096);
        ALLOC_GPE_RESOURCE(frame_statics_streamout_data_destination_buffer,
                           "frame statics streamout date destination buffer",
                           res_size);

        //res_size = (ALIGN(width, GEN10_HEVC_ENC_MAX_LCU_SIZE) + 2) * 64 * 8 * 2;
        res_size = ALIGN(frame_info->frame_width, 64) * 1024 + 2048;
        res_size = res_size << 1;
        ALLOC_GPE_RESOURCE(sse_source_pixel_rowstore_buffer,
                           "sse source pixel rowstore buffer",
                           res_size);
    }

    return 0;

FAIL:
    return -1;
}

void
gen10_hevc_enc_free_common_resource(struct gen10_hevc_enc_common_res *common_res)
{
    int i;

    i965_free_gpe_resource(&common_res->compressed_bitstream.gpe_res);
    i965_free_gpe_resource(&common_res->uncompressed_pic.gpe_res);
    i965_free_gpe_resource(&common_res->reconstructed_pic.gpe_res);

    for (i = 0; i < 16; i++)
        if (common_res->reference_pics[i].surface_id != VA_INVALID_ID)
            i965_free_gpe_resource(&common_res->reference_pics[i].gpe_res);

    i965_free_gpe_resource(&common_res->deblocking_filter_line_buffer);
    i965_free_gpe_resource(&common_res->deblocking_filter_tile_line_buffer);
    i965_free_gpe_resource(&common_res->deblocking_filter_tile_column_buffer);
    i965_free_gpe_resource(&common_res->metadata_line_buffer);
    i965_free_gpe_resource(&common_res->metadata_tile_line_buffer);
    i965_free_gpe_resource(&common_res->metadata_tile_column_buffer);
    i965_free_gpe_resource(&common_res->sao_line_buffer);
    i965_free_gpe_resource(&common_res->sao_tile_line_buffer);
    i965_free_gpe_resource(&common_res->sao_tile_column_buffer);
    i965_free_gpe_resource(&common_res->streamout_data_destination_buffer);
    i965_free_gpe_resource(&common_res->picture_status_buffer);
    i965_free_gpe_resource(&common_res->ildb_streamout_buffer);
    i965_free_gpe_resource(&common_res->sao_streamout_data_destination_buffer);
    i965_free_gpe_resource(&common_res->frame_statics_streamout_data_destination_buffer);
    i965_free_gpe_resource(&common_res->sse_source_pixel_rowstore_buffer);
}

void
gen10_hevc_enc_init_status_buffer(VADriverContextP ctx,
                                  struct encode_state *encode_state,
                                  struct intel_encoder_context *encoder_context,
                                  struct gen10_hevc_enc_status_buffer *status_buffer)
{
    struct i965_coded_buffer_segment *coded_buffer_segment;
    uint32_t base_offset;
    char *pbuffer;
    dri_bo *bo;

    bo = encode_state->coded_buf_object->buffer_store->bo;

    i965_free_gpe_resource(&status_buffer->gpe_res);
    i965_dri_object_to_buffer_gpe_resource(&status_buffer->gpe_res, bo);

    status_buffer->status_size = ALIGN(sizeof(struct gen10_hevc_enc_status), 64);

    status_buffer->mmio_bytes_per_frame_offset = GEN10_MMIO_HCP_ENC_BITSTREAM_BYTECOUNT_FRAME_OFFSET;
    status_buffer->mmio_bs_frame_no_header_offset = GEN10_MMIO_HCP_ENC_BITSTREAM_BYTECOUNT_FRAME_NO_HEADER_OFFSET;
    status_buffer->mmio_image_mask_offset = GEN10_MMIO_HCP_ENC_IMAGE_STATUS_MASK_OFFSET;
    status_buffer->mmio_image_ctrl_offset = GEn10_MMIO_HCP_ENC_IMAGE_STATUS_CTRL_OFFSET;
    status_buffer->mmio_qp_status_offset = GEN10_MMIO_HCP_ENC_QP_STATE_OFFSET;
    status_buffer->mmio_bs_se_bitcount_offset = GEN10_MMIO_HCP_ENC_BITSTREAM_SE_BITCOUNT_FRAME_OFFSET;

    base_offset = offsetof(struct i965_coded_buffer_segment, codec_private_data);
    status_buffer->status_image_mask_offset = base_offset +
                                              offsetof(struct gen10_hevc_enc_status, image_status_mask);
    status_buffer->status_image_ctrl_offset = base_offset +
                                              offsetof(struct gen10_hevc_enc_status, image_status_ctrl);
    status_buffer->status_bytes_per_frame_offset = base_offset +
                                                   offsetof(struct gen10_hevc_enc_status, bytes_per_frame);
    status_buffer->status_pass_num_offset = base_offset +
                                            offsetof(struct gen10_hevc_enc_status, pass_number);
    status_buffer->status_media_state_offset = base_offset +
                                               offsetof(struct gen10_hevc_enc_status, media_state);
    status_buffer->status_qp_status_offset = base_offset +
                                             offsetof(struct gen10_hevc_enc_status, qp_status);
    status_buffer->status_bs_se_bitcount_offset = base_offset +
                                                  offsetof(struct gen10_hevc_enc_status, bs_se_bitcount);

    dri_bo_map(bo, 1);

    coded_buffer_segment = (struct i965_coded_buffer_segment *)bo->virtual;
    coded_buffer_segment->mapped = 0;
    coded_buffer_segment->codec = encoder_context->codec;
    coded_buffer_segment->status_support = 1;

    pbuffer = bo->virtual + base_offset;
    memset(pbuffer, 0, status_buffer->status_size);

    dri_bo_unmap(bo);
}

void
gen10_hevc_enc_init_lambda_param(struct gen10_hevc_enc_lambda_param *param,
                                 int bit_depth_luma_minus8,
                                 int bit_depth_chroma_minus8)
{
    double qp_temp, lambda_double, qp_factor;
    int qp, qp_max[2], qp_offset[2], shift_qp = 12;
    uint32_t lambda = 0;
    int i;

    memset(param, 0, sizeof(*param));

    qp_offset[0] = 6 * bit_depth_luma_minus8;
    qp_offset[1] = 6 * bit_depth_chroma_minus8;
    qp_max[0] = 52 + qp_offset[0];
    qp_max[1] = 52 + qp_offset[1];

    qp_factor = 0.25 * 0.65;
    for (i = 0; i < 2; i++) {
        for (qp = 0; qp < qp_max[i]; qp++) {
            qp_temp = (double)qp - qp_offset[i] - shift_qp;
            lambda_double = qp_factor * pow(2.0, qp_temp / 3.0);
            lambda_double = lambda_double * 16 + 0.5;
            lambda_double = (lambda_double > 65535) ? 65535 : lambda_double;
            lambda = (uint32_t)floor(lambda_double);
            param->lambda_intra[i][qp] = (uint16_t)lambda;
        }
    }

    qp_factor = 0.55;
    for (i = 0; i < 2; i++) {
        for (qp = 0; qp < qp_max[i]; qp++) {
            qp_temp = (double)qp - qp_offset[i] - shift_qp;
            lambda_double = qp_factor * pow(2.0, qp_temp / 3.0);
            if (i == 0)
                lambda_double *= MAX(1.00, MIN(1.6, 1.0 + 0.6 / 12.0 * (qp_temp - 10.0)));
            else
                lambda_double *= MAX(0.95, MIN(1.2, 0.25 / 12.0 * (qp_temp - 10.0) + 0.95));
            lambda_double = lambda_double * 16 + 0.5;
            lambda = (uint32_t)floor(lambda_double);
            lambda_double = (lambda_double > 0xffff) ? 0xffff : lambda_double;
            lambda = MIN(0xffff, lambda);
            param->lambda_inter[i][qp] = (uint16_t)lambda;
        }
    }
}

static void
hevc_hcp_set_qm_state(VADriverContextP ctx,
                      struct intel_batchbuffer *batch,
                      int size_id,
                      int color_component,
                      int prediction_type,
                      int dc_coefficient,
                      uint8_t *qm_buf,
                      int qm_length)
{
    gen10_hcp_qm_state_param param;

    memset(&param, 0, sizeof(param));
    param.dw1.prediction_type = prediction_type;
    param.dw1.size_id = size_id;
    param.dw1.color_component = color_component;
    param.dw1.dc_coefficient = dc_coefficient;
    memcpy(param.quant_matrix, qm_buf, qm_length);
    gen10_hcp_qm_state(ctx, batch, &param);
}

static void
hevc_hcp_set_fqm_state(VADriverContextP ctx,
                       struct intel_batchbuffer *batch,
                       int size_id,
                       int color_component,
                       int prediction_type,
                       int forward_dc_coeff,
                       uint16_t *fqm_buf,
                       int fqm_length)
{
    gen10_hcp_fqm_state_param param;

    memset(&param, 0, sizeof(param));
    param.dw1.prediction_type = prediction_type;
    param.dw1.size_id = size_id;
    param.dw1.color_component = color_component;
    param.dw1.forward_dc_coeff = forward_dc_coeff;
    memcpy(param.forward_quant_matrix, fqm_buf, fqm_length * sizeof(uint16_t));
    gen10_hcp_fqm_state(ctx, batch, &param);
}

void
gen10_hevc_enc_hcp_set_qm_fqm_states(VADriverContextP ctx,
                                     struct intel_batchbuffer *batch,
                                     struct gen10_hevc_enc_frame_info *frame_info)
{
    int dc_coefficient, forward_dc_coeff;
    uint8_t *real_qm;
    uint16_t *real_fqm;
    int comps, len;
    int i, j, m;

    for (m = 0; m < 4; m++) {
        comps = (m == 3) ? 1 : 3;
        len = (m == 0) ? 16 : 64;

        for (i = 0; i < comps; i++) {
            for (j = 0; j < 2; j++) {
                real_qm = frame_info->qm_matrix[m][i][j];

                if (i == 0)
                    real_fqm = frame_info->fqm_matrix[m][j];

                if (m == 2 || m == 3) {
                    dc_coefficient = frame_info->qm_dc_matrix[m - 2][i][j];

                    if (i == 0)
                        forward_dc_coeff = frame_info->fqm_dc_matrix[m - 2][j];
                } else {
                    dc_coefficient = 0;
                    forward_dc_coeff = 0;
                }

                hevc_hcp_set_qm_state(ctx, batch, m, i, j, dc_coefficient,
                                      real_qm, len);

                if (i == 0)
                    hevc_hcp_set_fqm_state(ctx, batch, m, i, j, forward_dc_coeff,
                                           real_fqm, len);
            }
        }
    }
}

static void
gen10_hevc_enc_hcp_set_ref_idx_state(VADriverContextP ctx,
                                     struct intel_batchbuffer *batch,
                                     VAEncPictureParameterBufferHEVC *pic_param,
                                     VAEncSliceParameterBufferHEVC *slice_param,
                                     int list_index)
{
    gen10_hcp_ref_idx_state_param param;
    VAPictureHEVC *ref_pic, *cur_pic;
    int weighted_pred_flag;
    int i, j;

    assert(list_index < 2);

    memset(&param, 0, sizeof(param));

    param.dw1.ref_pic_list_num = list_index;
    param.dw1.num_ref_idx_active_minus1 = list_index == 0 ? slice_param->num_ref_idx_l0_active_minus1 :
                                          slice_param->num_ref_idx_l1_active_minus1;

    cur_pic = &pic_param->decoded_curr_pic;
    weighted_pred_flag = (pic_param->pic_fields.bits.weighted_pred_flag &&
                          slice_param->slice_type == HEVC_SLICE_P) ||
                         (pic_param->pic_fields.bits.weighted_bipred_flag &&
                          slice_param->slice_type == HEVC_SLICE_B);

    for (i = 0; i < 16; i++) {
        if (i < MIN(param.dw1.num_ref_idx_active_minus1 + 1, 15)) {
            if (list_index == 0)
                ref_pic = &slice_param->ref_pic_list0[i];
            else
                ref_pic = &slice_param->ref_pic_list1[i];

            j = hevc_enc_map_pic_index(ref_pic->picture_id,
                                       pic_param->reference_frames, 8);
            if (j >= 0) {
                param.ref_list_entry[i].ref_pic_tb_value = CLAMP(-128, 127,
                                                                 cur_pic->pic_order_cnt - ref_pic->pic_order_cnt) & 0xff;
                param.ref_list_entry[i].ref_pic_frame_id = j;
                param.ref_list_entry[i].chroma_weight_flag = weighted_pred_flag;
                param.ref_list_entry[i].luma_weight_flag = weighted_pred_flag;
                param.ref_list_entry[i].long_term_ref_flag = !!(ref_pic->flags &
                                                                VA_PICTURE_HEVC_LONG_TERM_REFERENCE);
            }
        }
    }

    gen10_hcp_ref_idx_state(ctx, batch, &param);
}

void
gen10_hevc_enc_hcp_set_ref_idx_lists(VADriverContextP ctx,
                                     struct intel_batchbuffer *batch,
                                     VAEncPictureParameterBufferHEVC *pic_param,
                                     VAEncSliceParameterBufferHEVC *slice_param)
{
    gen10_hevc_enc_hcp_set_ref_idx_state(ctx, batch, pic_param, slice_param, 0);
    if (slice_param->slice_type == HEVC_SLICE_B)
        gen10_hevc_enc_hcp_set_ref_idx_state(ctx, batch, pic_param, slice_param, 1);
}

void
gen10_hevc_enc_hcp_set_weight_offsets(VADriverContextP ctx,
                                      struct intel_batchbuffer *batch,
                                      VAEncPictureParameterBufferHEVC *pic_param,
                                      VAEncSliceParameterBufferHEVC *slice_param)
{
    gen10_hcp_weightoffset_state_param param;
    int enable;
    int i, j;

    for (i = 0; i < 2; i++) {
        if (i == 0 &&
            pic_param->pic_fields.bits.weighted_pred_flag &&
            slice_param->slice_type == HEVC_SLICE_P)
            enable = 1;
        else if (i == 1 &&
                 pic_param->pic_fields.bits.weighted_bipred_flag &&
                 slice_param->slice_type == HEVC_SLICE_B)
            enable = 1;
        else
            enable = 0;

        if (enable) {
            memset(&param, 0, sizeof(param));

            param.dw1.ref_pic_list_num = i;

            if (i == 0) {
                for (j = 0; j < 15; j++) {
                    param.luma_offset[j].delta_luma_weight = slice_param->delta_luma_weight_l0[j];
                    param.luma_offset[j].luma_offset = slice_param->luma_offset_l0[j];

                    param.chroma_offset[j].delta_chroma_weight_0 = slice_param->delta_chroma_weight_l0[j][0];
                    param.chroma_offset[j].chroma_offset_0 = slice_param->chroma_offset_l0[j][0];
                    param.chroma_offset[j].delta_chroma_weight_1 = slice_param->delta_chroma_weight_l0[j][1];
                    param.chroma_offset[j].chroma_offset_1 = slice_param->chroma_offset_l0[j][1];
                }
            } else {
                for (j = 0; j < 15; j++) {
                    param.luma_offset[j].delta_luma_weight = slice_param->delta_luma_weight_l1[j];
                    param.luma_offset[j].luma_offset = slice_param->luma_offset_l1[j];

                    param.chroma_offset[j].delta_chroma_weight_0 = slice_param->delta_chroma_weight_l1[j][0];
                    param.chroma_offset[j].chroma_offset_0 = slice_param->chroma_offset_l1[j][0];
                    param.chroma_offset[j].delta_chroma_weight_1 = slice_param->delta_chroma_weight_l1[j][1];
                    param.chroma_offset[j].chroma_offset_1 = slice_param->chroma_offset_l1[j][1];
                }
            }

            gen10_hcp_weightoffset_state(ctx, batch, &param);
        }
    }
}

VAStatus
gen10_hevc_enc_ensure_surface(VADriverContextP ctx,
                              struct object_surface *obj_surface,
                              int bit_depth_minus8,
                              int reallocate_flag)
{
    VAStatus va_status = VA_STATUS_SUCCESS;
    uint32_t fourcc = VA_FOURCC_NV12;
    int update = 0;

    if (!obj_surface) {
        va_status = VA_STATUS_ERROR_INVALID_PARAMETER;

        goto EXIT;
    }

    if (bit_depth_minus8 > 0) {
        if (obj_surface->fourcc != VA_FOURCC_P010) {
            update = 1;
            fourcc = VA_FOURCC_P010;
        }
    } else if (obj_surface->fourcc != VA_FOURCC_NV12) {
        update = 1;
        fourcc = VA_FOURCC_NV12;
    }

    if (!obj_surface->bo || update) {
        if (reallocate_flag) {
            struct i965_driver_data * const i965 = i965_driver_data(ctx);

            i965_destroy_surface_storage(obj_surface);

            va_status = i965_check_alloc_surface_bo(ctx,
                                                    obj_surface,
                                                    i965->codec_info->has_tiled_surface,
                                                    fourcc,
                                                    SUBSAMPLE_YUV420);
        } else
            va_status = VA_STATUS_ERROR_INVALID_PARAMETER;
    }

EXIT:
    return va_status;
}

static void
hevc_get_max_mbps(uint32_t level_idc,
                  uint32_t *max_bps,
                  uint64_t *max_bps_per_pic)
{
    switch (level_idc) {
    case 30:
        *max_bps = 552960;
        *max_bps_per_pic = 36864;
        break;
    case 60:
        *max_bps = 3686400;
        *max_bps_per_pic = 122880;
        break;
    case 63:
        *max_bps = 7372800;
        *max_bps_per_pic = 245760;
        break;
    case 90:
        *max_bps = 16588800;
        *max_bps_per_pic = 552760;
        break;
    case 93:
        *max_bps = 33177600;
        *max_bps_per_pic = 983040;
        break;
    case 120:
        *max_bps = 66846720;
        *max_bps_per_pic = 2228224;
        break;
    case 123:
        *max_bps = 133693440;
        *max_bps_per_pic = 2228224;
        break;
    case 150:
        *max_bps = 267386880;
        *max_bps_per_pic = 8912896;
        break;
    case 153:
        *max_bps = 534773760;
        *max_bps_per_pic = 8912896;
        break;
    case 156:
        *max_bps = 1069547520;
        *max_bps_per_pic = 8912896;
        break;
    case 180:
        *max_bps = 1069547520;
        *max_bps_per_pic = 35651584;
        break;
    case 183:
        *max_bps = 2139095040;
        *max_bps_per_pic = 35651584;
        break;
    case 186:
        *max_bps = 4278190080;
        *max_bps_per_pic = 35651584;
        break;
    default:
        *max_bps = 16588800;
        *max_bps_per_pic = 552760;
        break;
    }
}

uint32_t
gen10_hevc_enc_get_profile_level_max_frame(VAEncSequenceParameterBufferHEVC *seq_param,
                                           uint32_t user_max_frame_size,
                                           uint32_t frame_rate)
{
    int bit_depth_minus8 = seq_param->seq_fields.bits.bit_depth_luma_minus8;
    uint64_t max_byte_per_pic, max_byte_per_pic_not0;
    int level_idc = seq_param->general_level_idc;
    uint32_t profile_level_max_frame, max_mbps;
    double format_factor = 1.5;
    double min_cr_scale = 1.0;
    int min_cr;

    assert(seq_param->seq_fields.bits.chroma_format_idc == 1);

    if (level_idc == 186 || level_idc == 150)
        min_cr = 6;
    else if (level_idc > 150)
        min_cr = 8;
    else if (level_idc > 93)
        min_cr = 4;
    else
        min_cr = 2;

    format_factor = bit_depth_minus8 == 2 ? 1.875 :
                    bit_depth_minus8 == 4 ? 2.25 : 1.5;

    min_cr_scale *= min_cr;
    format_factor /= min_cr_scale;

    hevc_get_max_mbps(level_idc, &max_mbps, &max_byte_per_pic);

    max_byte_per_pic_not0 = (uint64_t)((((float_t)max_mbps * (float_t)100) / (float_t)frame_rate)  * format_factor);

    if (user_max_frame_size) {
        profile_level_max_frame = (uint32_t)MIN(user_max_frame_size, max_byte_per_pic);
        profile_level_max_frame = (uint32_t)MIN(max_byte_per_pic_not0, profile_level_max_frame);
    } else
        profile_level_max_frame = (uint32_t)MIN(max_byte_per_pic_not0, max_byte_per_pic);

    return MIN(profile_level_max_frame,
               seq_param->pic_width_in_luma_samples * seq_param->pic_height_in_luma_samples);
}

uint32_t
gen10_hevc_enc_get_max_num_slices(VAEncSequenceParameterBufferHEVC *seq_param)
{
    uint32_t max_num_slices = 0;

    switch (seq_param->general_level_idc) {
    case 30:
        max_num_slices = 16;
        break;
    case 60:
        max_num_slices = 16;
        break;
    case 63:
        max_num_slices = 20;
        break;
    case 90:
        max_num_slices = 30;
        break;
    case 93:
        max_num_slices = 40;
        break;
    case 120:
        max_num_slices = 75;
        break;
    case 123:
        max_num_slices = 75;
        break;
    case 150:
        max_num_slices = 200;
        break;
    case 153:
        max_num_slices = 200;
        break;
    case 156:
        max_num_slices = 200;
        break;
    case 180:
        max_num_slices = 600;
        break;
    case 183:
        max_num_slices = 600;
        break;
    case 186:
        max_num_slices = 600;
        break;
    default:
        max_num_slices = 0;
        break;
    }

    return max_num_slices;
}

static
uint32_t gen10_hevc_get_start_code_offset(unsigned char *ptr,
                                          uint32_t size)
{
    uint32_t count = 0;

    while (count < size && *ptr != 0x01) {
        if (*ptr != 0)
            break;

        count++;
        ptr++;
    }

    return count + 1;
}

static
uint32_t gen10_hevc_get_emulation_num(unsigned char *ptr,
                                      uint32_t size)
{
    uint32_t emulation_num = 0;
    uint32_t header_offset = 0;
    uint32_t zero_count = 0;
    int i = 0;

    header_offset = gen10_hevc_get_start_code_offset(ptr, size);
    ptr += header_offset;

    for (i = 0 ; i < (size - header_offset); i++, ptr++) {
        if (zero_count == 2 && !(*ptr & 0xFC)) {
            zero_count = 0;
            emulation_num++;
        }

        if (*ptr == 0x00)
            zero_count++;
        else
            zero_count = 0;
    }

    return emulation_num;
}

#define HEVC_ENC_START_CODE_NAL_OFFSET                  (2)

uint32_t
gen10_hevc_enc_get_pic_header_size(struct encode_state *encode_state)
{
    VAEncPackedHeaderParameterBuffer *param = NULL;
    uint32_t header_begin = 0;
    uint32_t accum_size = 0;
    unsigned char *header_data = NULL;
    uint32_t length_in_bytes = 0;
    int packed_type = 0;
    int idx = 0, count = 0, idx_offset = 0;
    int i = 0, slice_idx = 0, start_index = 0;

    for (i = 0; i < 4; i++) {
        idx_offset = 0;
        switch (i) {
        case 0:
            packed_type = VAEncPackedHeaderHEVC_VPS;
            break;
        case 1:
            packed_type = VAEncPackedHeaderHEVC_VPS;
            idx_offset = 1;
            break;
        case 2:
            packed_type = VAEncPackedHeaderHEVC_PPS;
            break;
        case 3:
            packed_type = VAEncPackedHeaderHEVC_SEI;
            break;
        default:
            break;
        }

        idx = va_enc_packed_type_to_idx(packed_type) + idx_offset;
        if (encode_state->packed_header_data[idx]) {
            param = (VAEncPackedHeaderParameterBuffer *)encode_state->packed_header_param[idx]->buffer;
            header_data = (unsigned char *)encode_state->packed_header_data[idx]->buffer;
            length_in_bytes = (param->bit_length + 7) / 8;

            header_begin = gen10_hevc_get_start_code_offset(header_data, length_in_bytes) +
                           HEVC_ENC_START_CODE_NAL_OFFSET;

            accum_size += length_in_bytes;
            if (!param->has_emulation_bytes)
                accum_size += gen10_hevc_get_emulation_num(header_data,
                                                           length_in_bytes);
        }
    }

    for (slice_idx = 0; slice_idx < encode_state->num_slice_params_ext; slice_idx++) {
        count = encode_state->slice_rawdata_count[slice_idx];
        start_index = encode_state->slice_rawdata_index[slice_idx] &
                      SLICE_PACKED_DATA_INDEX_MASK;

        if (start_index >= 5)
            break;

        for (i = 0; i < count; i++) {
            param = (VAEncPackedHeaderParameterBuffer *)
                    (encode_state->packed_header_params_ext[start_index + i]->buffer);

            if (param->type == VAEncPackedHeaderSlice)
                continue;

            header_data = (unsigned char *)encode_state->packed_header_data[start_index]->buffer;
            length_in_bytes = (param->bit_length + 7) / 8;

            accum_size += length_in_bytes;
            if (!param->has_emulation_bytes)
                accum_size += gen10_hevc_get_emulation_num(header_data,
                                                           length_in_bytes);
        }
    }

    header_begin = MIN(header_begin, accum_size);

    return ((accum_size - header_begin) * 8);
}


<!DOCTYPE html>

<meta charset="utf-8">
<title>CSS Images Module Level 3: image-orientation: from-image</title>
<link rel="author" title="Stephen Chenney" href="mailto:schenney@chromium.org">
<link rel="help" href="https://drafts.csswg.org/css-images-3/#propdef-image-orientation">
<link rel="match" href="reference/image-orientation-from-image-ref.html">
<meta name=fuzzy content="10;100">

The images should rotate respecting their EXIF orientation because
       image-orientation: from-image is specified.

Normal

Flipped horizontally

Rotated 180°

Flipped vertically

Rotated 90° CCW and flipped vertically

Rotated 90° CW

Rotated 90° CW and flipped vertically

Rotated 90° CCW

Undefined (invalid value)


### Virtualized List

<!--start-code-->

```js
/**
 * import data from
 * https://github.com/rsuite/rsuite/blob/master/docs/public/data/en/city-simplified.json
 */

const instance = (
  <div>
    <CheckTreePicker
      virtualized
      defaultExpandAll
      data={data}
      cascade={false}
      style={{ width: 280 }}
    />
  </div>
);
ReactDOM.render(instance);
```

<!--end-code-->


// Copyright 2017 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

// Flags: --allow-natives-syntax

// Test Reflect.apply with wrong number of arguments.
(function() {
  "use strict";
  function bar() { return this; }
  function foo() { return Reflect.apply(bar); }

  %PrepareFunctionForOptimization(foo);
  assertThrows(foo);
  assertThrows(foo);
  %OptimizeFunctionOnNextCall(foo);
  assertThrows(foo);
})();
(function() {
  "use strict";
  function bar() { return this; }
  function foo() { return Reflect.apply(bar, this); }

  %PrepareFunctionForOptimization(foo);
  assertThrows(foo);
  assertThrows(foo);
  %OptimizeFunctionOnNextCall(foo);
  assertThrows(foo);
})();
(function() {
  "use strict";
  function bar() { return this; }
  function foo() { return Reflect.apply(bar, this, arguments, this); }

  %PrepareFunctionForOptimization(foo);
  assertEquals(42, foo.call(42));
  assertEquals(42, foo.call(42));
  %OptimizeFunctionOnNextCall(foo);
  assertEquals(42, foo.call(42));
})();

// Test Reflect.apply within try/catch.
(function() {
  "use strict";
  function foo(bar) {
    try {
      return Reflect.apply(bar, bar, arguments);
    } catch (e) {
      return 1;
    }
  }

  %PrepareFunctionForOptimization(foo);
  assertEquals(1, foo());
  assertEquals(1, foo());
  %OptimizeFunctionOnNextCall(foo);
  assertEquals(1, foo());
})();
(function() {
  "use strict";
  function foo(bar) {
    try {
      return Reflect.apply(bar, bar, bar);
    } catch (e) {
      return 1;
    }
  }

  %PrepareFunctionForOptimization(foo);
  assertEquals(1, foo());
  assertEquals(1, foo());
  %OptimizeFunctionOnNextCall(foo);
  assertEquals(1, foo());
})();

// Test proper order of callable check and array-like iteration
// in Reflect.apply.
(function() {
  var dummy_length_counter = 0;
  var dummy = { get length() { ++dummy_length_counter; return 0; } };

  function foo() {
    return Reflect.apply(undefined, this, dummy);
  }

  %PrepareFunctionForOptimization(foo);
  assertThrows(foo, TypeError);
  assertThrows(foo, TypeError);
  %OptimizeFunctionOnNextCall(foo);
  assertThrows(foo, TypeError);
  assertEquals(0, dummy_length_counter);
})();
(function() {
  var dummy_length_counter = 0;
  var dummy = { get length() { ++dummy_length_counter; return 0; } };

  function foo() {
    return Reflect.apply(null, this, dummy);
  }

  %PrepareFunctionForOptimization(foo);
  assertThrows(foo, TypeError);
  assertThrows(foo, TypeError);
  %OptimizeFunctionOnNextCall(foo);
  assertThrows(foo, TypeError);
  assertEquals(0, dummy_length_counter);
})();
(function() {
  var dummy_length_counter = 0;
  var dummy = { get length() { ++dummy_length_counter; return 0; } };

  function foo() {
    return Reflect.apply(null, this, dummy);
  }

  %PrepareFunctionForOptimization(foo);
  assertThrows(foo, TypeError);
  assertThrows(foo, TypeError);
  %OptimizeFunctionOnNextCall(foo);
  assertThrows(foo, TypeError);
  assertEquals(0, dummy_length_counter);
})();


/*
Copyright (C) 1999-2006 Id Software, Inc. and contributors.
For a list of contributors, see the accompanying CONTRIBUTORS file.

This file is part of GtkRadiant.

GtkRadiant 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.

GtkRadiant is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with GtkRadiant; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
*/

#ifndef QD_SKELETONS_H
#define QD_SKELETONS_H

#include "placement.h"

typedef struct Placement_d_s
{
	vec3d_t origin;
	vec3d_t direction;
	vec3d_t up;
} Placement_d_t;

typedef struct QD_SkeletalJoint_s
{
	Placement_d_t placement;
	vec3d_t		rotation;
} QD_SkeletalJoint_t;

#define NUM_CLUSTERS 8

typedef struct IntListNode_s
{
	int data;
	struct IntListNode_s *next;
} IntListNode_t;  // gaak

typedef struct Skeletalfmheader_s
{
	int type;
	int clustered;
	int references;

	int *clusters[NUM_CLUSTERS];
	IntListNode_t *vertLists[NUM_CLUSTERS];
	int num_verts[NUM_CLUSTERS + 1];
	int new_num_verts[NUM_CLUSTERS + 1];

	float scaling[3];
	float rotation[3];
	float translation[3];
} Skeletalfmheader_t;

#define SKELETAL_NAME_MAX 32

extern Skeletalfmheader_t g_skelModel;

void ClearSkeletalModel();
void GrabModelTransform(char *frame);
void GrabSkeletalFrame(char *frame);
void GrabReferencedFrame(char *frame);

// Reference Stuff
#define NUM_REFERENCES 8

#define REF_MAX_POINTS	16
#define REF_MAX_STRLEN	32

// We're assuming no more than 16 reference points, with no more than 32 characters in the name
extern char RefPointNameList[REF_MAX_POINTS][REF_MAX_STRLEN];
extern int	RefPointNum;

#endif


/*

Copyright (c) 2015, Project OSRM contributors
All rights reserved.

Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met:

Redistributions of source code must retain the above copyright notice, this list
of conditions and the following disclaimer.
Redistributions in binary form must reproduce the above copyright notice, this
list of conditions and the following disclaimer in the documentation and/or
other materials provided with the distribution.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

*/

#include "description_factory.hpp"

#include "../algorithms/polyline_formatter.hpp"
#include "../data_structures/coordinate_calculation.hpp"
#include "../data_structures/internal_route_result.hpp"
#include "../data_structures/turn_instructions.hpp"
#include "../util/container.hpp"
#include "../util/integer_range.hpp"
#include "../typedefs.h"

DescriptionFactory::DescriptionFactory() : entire_length(0) { via_indices.push_back(0); }

std::vector<unsigned> const &DescriptionFactory::GetViaIndices() const { return via_indices; }

void DescriptionFactory::SetStartSegment(const PhantomNode &source, const bool traversed_in_reverse)
{
    start_phantom = source;
    const EdgeWeight segment_duration =
        (traversed_in_reverse ? source.reverse_weight : source.forward_weight);
    const TravelMode travel_mode =
        (traversed_in_reverse ? source.backward_travel_mode : source.forward_travel_mode);
    AppendSegment(source.location, PathData(0, source.name_id, TurnInstruction::HeadOn,
                                            segment_duration, travel_mode));
    BOOST_ASSERT(path_description.back().duration == segment_duration);
}

void DescriptionFactory::SetEndSegment(const PhantomNode &target,
                                       const bool traversed_in_reverse,
                                       const bool is_via_location)
{
    target_phantom = target;
    const EdgeWeight segment_duration =
        (traversed_in_reverse ? target.reverse_weight : target.forward_weight);
    const TravelMode travel_mode =
        (traversed_in_reverse ? target.backward_travel_mode : target.forward_travel_mode);
    path_description.emplace_back(target.location, target.name_id, segment_duration, 0.f,
                                  is_via_location ? TurnInstruction::ReachViaLocation
                                                  : TurnInstruction::NoTurn,
                                  true, true, travel_mode);
    BOOST_ASSERT(path_description.back().duration == segment_duration);
}

void DescriptionFactory::AppendSegment(const FixedPointCoordinate &coordinate,
                                       const PathData &path_point)
{
    // if the start location is on top of a node, the first movement might be zero-length,
    // in which case we dont' add a new description, but instead update the existing one
    if ((1 == path_description.size()) && (path_description.front().location == coordinate))
    {
        if (path_point.segment_duration > 0)
        {
            path_description.front().name_id = path_point.name_id;
            path_description.front().travel_mode = path_point.travel_mode;
        }
        return;
    }

    // make sure mode changes are announced, even when there otherwise is no turn
    const TurnInstruction turn = [&]() -> TurnInstruction
    {
        if (TurnInstruction::NoTurn == path_point.turn_instruction &&
            path_description.front().travel_mode != path_point.travel_mode &&
            path_point.segment_duration > 0)
        {
            return TurnInstruction::GoStraight;
        }
        return path_point.turn_instruction;
    }();

    path_description.emplace_back(coordinate, path_point.name_id, path_point.segment_duration, 0.f,
                                  turn, path_point.travel_mode);
}

osrm::json::Value DescriptionFactory::AppendGeometryString(const bool return_encoded)
{
    if (return_encoded)
    {
        return PolylineFormatter().printEncodedString(path_description);
    }
    return PolylineFormatter().printUnencodedString(path_description);
}

void DescriptionFactory::BuildRouteSummary(const double distance, const unsigned time)
{
    summary.source_name_id = start_phantom.name_id;
    summary.target_name_id = target_phantom.name_id;
    summary.BuildDurationAndLengthStrings(distance, time);
}

void DescriptionFactory::Run(const unsigned zoom_level)
{
    if (path_description.empty())
    {
        return;
    }

    /** starts at index 1 */
    path_description[0].length = 0.f;
    for (const auto i : osrm::irange<std::size_t>(1, path_description.size()))
    {
        // move down names by one, q&d hack
        path_description[i - 1].name_id = path_description[i].name_id;
        path_description[i].length = coordinate_calculation::euclidean_distance(
            path_description[i - 1].location, path_description[i].location);
    }

    /*Simplify turn instructions
    Input :
    10. Turn left on B 36 for 20 km
    11. Continue on B 35; B 36 for 2 km
    12. Continue on B 36 for 13 km

    becomes:
    10. Turn left on B 36 for 35 km
    */
    // TODO: rework to check only end and start of string.
    //      stl string is way to expensive

    //    unsigned lastTurn = 0;
    //    for(unsigned i = 1; i < path_description.size(); ++i) {
    //        string1 = sEngine.GetEscapedNameForNameID(path_description[i].name_id);
    //        if(TurnInstruction::GoStraight == path_description[i].turn_instruction) {
    //            if(std::string::npos != string0.find(string1+";")
    //                  || std::string::npos != string0.find(";"+string1)
    //                  || std::string::npos != string0.find(string1+" ;")
    //                    || std::string::npos != string0.find("; "+string1)
    //                    ){
    //                SimpleLogger().Write() << "->next correct: " << string0 << " contains " <<
    //                string1;
    //                for(; lastTurn != i; ++lastTurn)
    //                    path_description[lastTurn].name_id = path_description[i].name_id;
    //                path_description[i].turn_instruction = TurnInstruction::NoTurn;
    //            } else if(std::string::npos != string1.find(string0+";")
    //                  || std::string::npos != string1.find(";"+string0)
    //                    || std::string::npos != string1.find(string0+" ;")
    //                    || std::string::npos != string1.find("; "+string0)
    //                    ){
    //                SimpleLogger().Write() << "->prev correct: " << string1 << " contains " <<
    //                string0;
    //                path_description[i].name_id = path_description[i-1].name_id;
    //                path_description[i].turn_instruction = TurnInstruction::NoTurn;
    //            }
    //        }
    //        if (TurnInstruction::NoTurn != path_description[i].turn_instruction) {
    //            lastTurn = i;
    //        }
    //        string0 = string1;
    //    }

    float segment_length = 0.;
    EdgeWeight segment_duration = 0;
    std::size_t segment_start_index = 0;

    for (const auto i : osrm::irange<std::size_t>(1, path_description.size()))
    {
        entire_length += path_description[i].length;
        segment_length += path_description[i].length;
        segment_duration += path_description[i].duration;
        path_description[segment_start_index].length = segment_length;
        path_description[segment_start_index].duration = segment_duration;

        if (TurnInstruction::NoTurn != path_description[i].turn_instruction)
        {
            BOOST_ASSERT(path_description[i].necessary);
            segment_length = 0;
            segment_duration = 0;
            segment_start_index = i;
        }
    }

    // Post-processing to remove empty or nearly empty path segments
    if (path_description.size() > 2 &&
        std::numeric_limits<float>::epsilon() > path_description.back().length)
    {
        path_description.pop_back();
        path_description.back().necessary = true;
        path_description.back().turn_instruction = TurnInstruction::NoTurn;
        target_phantom.name_id = (path_description.end() - 2)->name_id;
    }

    if (path_description.size() > 2 &&
        std::numeric_limits<float>::epsilon() > path_description.front().length)
    {
        path_description.erase(path_description.begin());
        path_description.front().turn_instruction = TurnInstruction::HeadOn;
        path_description.front().necessary = true;
        start_phantom.name_id = path_description.front().name_id;
    }

    // Generalize poly line
    polyline_generalizer.Run(path_description.begin(), path_description.end(), zoom_level);

    // fix what needs to be fixed else
    unsigned necessary_segments = 0; // a running index that counts the necessary pieces
    osrm::for_each_pair(
        path_description, [&](SegmentInformation &first, const SegmentInformation &second)
        {
            if (!first.necessary)
            {
                return;
            }

            ++necessary_segments;

            if (first.is_via_location)
            { // mark the end of a leg (of several segments)
                via_indices.push_back(necessary_segments);
            }

            const double angle = coordinate_calculation::bearing(first.location, second.location);
            first.bearing = static_cast<short>(angle * 10);
        });

    via_indices.push_back(necessary_segments + 1);
    BOOST_ASSERT(via_indices.size() >= 2);
    return;
}


package jwt_test

// Example HTTP auth using asymmetric crypto/RSA keys
// This is based on a (now outdated) example at https://gist.github.com/cryptix/45c33ecf0ae54828e63b

import (
	"bytes"
	"crypto/rsa"
	"fmt"
	"github.com/dgrijalva/jwt-go"
	"github.com/dgrijalva/jwt-go/request"
	"io"
	"io/ioutil"
	"log"
	"net"
	"net/http"
	"net/url"
	"strings"
	"time"
)

// location of the files used for signing and verification
const (
	privKeyPath = "test/sample_key"     // openssl genrsa -out app.rsa keysize
	pubKeyPath  = "test/sample_key.pub" // openssl rsa -in app.rsa -pubout > app.rsa.pub
)

var (
	verifyKey  *rsa.PublicKey
	signKey    *rsa.PrivateKey
	serverPort int
	// storing sample username/password pairs
	// don't do this on a real server
	users = map[string]string{
		"test": "known",
	}
)

// read the key files before starting http handlers
func init() {
	signBytes, err := ioutil.ReadFile(privKeyPath)
	fatal(err)

	signKey, err = jwt.ParseRSAPrivateKeyFromPEM(signBytes)
	fatal(err)

	verifyBytes, err := ioutil.ReadFile(pubKeyPath)
	fatal(err)

	verifyKey, err = jwt.ParseRSAPublicKeyFromPEM(verifyBytes)
	fatal(err)

	http.HandleFunc("/authenticate", authHandler)
	http.HandleFunc("/restricted", restrictedHandler)

	// Setup listener
	listener, err := net.ListenTCP("tcp", &net.TCPAddr{})
	serverPort = listener.Addr().(*net.TCPAddr).Port

	log.Println("Listening...")
	go func() {
		fatal(http.Serve(listener, nil))
	}()
}

var start func()

func fatal(err error) {
	if err != nil {
		log.Fatal(err)
	}
}

// Define some custom types were going to use within our tokens
type CustomerInfo struct {
	Name string
	Kind string
}

type CustomClaimsExample struct {
	*jwt.StandardClaims
	TokenType string
	CustomerInfo
}

func Example_getTokenViaHTTP() {
	// See func authHandler for an example auth handler that produces a token
	res, err := http.PostForm(fmt.Sprintf("http://localhost:%v/authenticate", serverPort), url.Values{
		"user": {"test"},
		"pass": {"known"},
	})
	if err != nil {
		fatal(err)
	}

	if res.StatusCode != 200 {
		fmt.Println("Unexpected status code", res.StatusCode)
	}

	// Read the token out of the response body
	buf := new(bytes.Buffer)
	io.Copy(buf, res.Body)
	res.Body.Close()
	tokenString := strings.TrimSpace(buf.String())

	// Parse the token
	token, err := jwt.ParseWithClaims(tokenString, &CustomClaimsExample{}, func(token *jwt.Token) (interface{}, error) {
		// since we only use the one private key to sign the tokens,
		// we also only use its public counter part to verify
		return verifyKey, nil
	})
	fatal(err)

	claims := token.Claims.(*CustomClaimsExample)
	fmt.Println(claims.CustomerInfo.Name)

	//Output: test
}

func Example_useTokenViaHTTP() {

	// Make a sample token
	// In a real world situation, this token will have been acquired from
	// some other API call (see Example_getTokenViaHTTP)
	token, err := createToken("foo")
	fatal(err)

	// Make request.  See func restrictedHandler for example request processor
	req, err := http.NewRequest("GET", fmt.Sprintf("http://localhost:%v/restricted", serverPort), nil)
	fatal(err)
	req.Header.Set("Authorization", fmt.Sprintf("Bearer %v", token))
	res, err := http.DefaultClient.Do(req)
	fatal(err)

	// Read the response body
	buf := new(bytes.Buffer)
	io.Copy(buf, res.Body)
	res.Body.Close()
	fmt.Println(buf.String())

	// Output: Welcome, foo
}

func createToken(user string) (string, error) {
	// create a signer for rsa 256
	t := jwt.New(jwt.GetSigningMethod("RS256"))

	// set our claims
	t.Claims = &CustomClaimsExample{
		&jwt.StandardClaims{
			// set the expire time
			// see http://tools.ietf.org/html/draft-ietf-oauth-json-web-token-20#section-4.1.4
			ExpiresAt: time.Now().Add(time.Minute * 1).Unix(),
		},
		"level1",
		CustomerInfo{user, "human"},
	}

	// Creat token string
	return t.SignedString(signKey)
}

// reads the form values, checks them and creates the token
func authHandler(w http.ResponseWriter, r *http.Request) {
	// make sure its post
	if r.Method != "POST" {
		w.WriteHeader(http.StatusBadRequest)
		fmt.Fprintln(w, "No POST", r.Method)
		return
	}

	user := r.FormValue("user")
	pass := r.FormValue("pass")

	log.Printf("Authenticate: user[%s] pass[%s]\n", user, pass)

	// check values
	if user != "test" || pass != "known" {
		w.WriteHeader(http.StatusForbidden)
		fmt.Fprintln(w, "Wrong info")
		return
	}

	tokenString, err := createToken(user)
	if err != nil {
		w.WriteHeader(http.StatusInternalServerError)
		fmt.Fprintln(w, "Sorry, error while Signing Token!")
		log.Printf("Token Signing error: %v\n", err)
		return
	}

	w.Header().Set("Content-Type", "application/jwt")
	w.WriteHeader(http.StatusOK)
	fmt.Fprintln(w, tokenString)
}

// only accessible with a valid token
func restrictedHandler(w http.ResponseWriter, r *http.Request) {
	// Get token from request
	token, err := request.ParseFromRequestWithClaims(r, request.OAuth2Extractor, &CustomClaimsExample{}, func(token *jwt.Token) (interface{}, error) {
		// since we only use the one private key to sign the tokens,
		// we also only use its public counter part to verify
		return verifyKey, nil
	})

	// If the token is missing or invalid, return error
	if err != nil {
		w.WriteHeader(http.StatusUnauthorized)
		fmt.Fprintln(w, "Invalid token:", err)
		return
	}

	// Token is valid
	fmt.Fprintln(w, "Welcome,", token.Claims.(*CustomClaimsExample).Name)
	return
}


typedef char BYTE;

int envValueAt(double input)
{
	static int *cluster = NULL;
	static int clusterSize;
	if (cluster == NULL)
		GetCluster(&clusterSize, &cluster);
	int ix = input*clusterSize;
	if (ix >= clusterSize)
		ix = clusterSize-1;
	return cluster[ix];
}

static void makeCircleBrush(int xoff, int yoff, int diameter, Screen *screen)
// Make a circle brush of given size on screen.
//
{
	if (diameter == 1){  // One pixel brush
		SetPixel(screen, envValueAt(1.0), xoff, yoff);
	} else {
		// The 16 bit arithmetic and the line buffer will both blow
		// if diameter is more than 255.

		// ASSERT(diameter <= 255);
		BYTE lineBuf[255];

		double x, y;
		int mid = diameter/2;
		int mid1;
		double start;
		// Odd and even sizes are handled pretty differently...
		if (diameter & 1) {
			start = 0;
			mid1 = mid;
		} else {
			start = 0.5;
			mid1 = mid-1;
		}
		double rad = diameter/2.0;
		double radSquared = rad*rad;
		double end = rad;
		int iy = 0;
		for (y = start; y < end;  y += 1.0) {
			double y2 = y*y;
			int ix = 0;
			for (x = start; x < end; x += 1.0) {
				double distSquared = y2 + x*x;
				BYTE color;
				if (distSquared <= radSquared) {
					double dist = sqrt(distSquared);
					color = envValueAt(1.0 - dist/rad);
				} else {
					color = 0;
				}
				lineBuf[mid+ix] = lineBuf[mid1-ix] = color;
				++ix;
			}
			SetBlock(screen, lineBuf, xoff, yoff+mid+iy, diameter, 1);
			SetBlock(screen, lineBuf, xoff, yoff+mid1-iy, diameter, 1);
			++iy;
		}
	}
}

showRow(int max)
// Show a whole row of brushes
{
	int width, height;
	GetSize(&width,&height);
	int x = 0, y = 0;
	int size = 1;
	for (;;) {
		if (size > max)
			break;
		if (x + size > width) {
			y += size;
			x = 0;
		}
		if (y + size > height)
			break;
		makeCircleBrush(x, y, size, GetPicScreen());
		size += 1;
		x += size;
	}
}

main()
{
	int x,y,left,right,key;
	int size = 10;

	for (;;) {
		WaitClick(&x,&y,&left,&right,&key);
		key &= 0xff;
		if (key == '+' && size < 100)
			++size;
		else if (key == '-' && size > 1)
			--size;
		else if (key == '#') {
			Qnumber(&size, 1, 255, "Set size of brush");
		}
		else if (key == '?')
			showRow(64);
		else if (key == 0x1b)
			break;
		if (left)
			makeCircleBrush(x,y,size,GetPicScreen());
		if (right)
			break;
	}
}


using System;
using System.Collections.Generic;
using System.Text;

namespace Bot.Builder.Community.Dialogs.ChoiceFlow.Extensions
{
    public static class EnumerableExtensions
    {
        public static IEnumerable<T> SelectRecursive<T>(this IEnumerable<T> source, Func<T, IEnumerable<T>> getChildren)
        {
            if (null == source) throw new ArgumentNullException("source");
            if (null == getChildren) return source;
            return SelectRecursiveIterator(source, getChildren);
        }

        private static IEnumerable<T> SelectRecursiveIterator<T>(IEnumerable<T> source, Func<T, IEnumerable<T>> getChildren)
        {
            var stack = new Stack<IEnumerator<T>>();

            try
            {
                stack.Push(source.GetEnumerator());
                while (0 != stack.Count)
                {
                    var iter = stack.Peek();
                    if (iter.MoveNext())
                    {
                        T current = iter.Current;
                        yield return current;

                        var children = getChildren(current);
                        if (null != children) stack.Push(children.GetEnumerator());
                    }
                    else
                    {
                        iter.Dispose();
                        stack.Pop();
                    }
                }
            }
            finally
            {
                while (0 != stack.Count)
                {
                    stack.Pop().Dispose();
                }
            }
        }
    }
}


const { execFileSync } = require('child_process');
execFileSync(`${__dirname}/install-nix`, { stdio: 'inherit' });


/**
 * Copyright (c) 2014 Microsoft Open Technologies, Inc.
 *
 *    Licensed under the Apache License, Version 2.0 (the "License"); you may
 *    not use this file except in compliance with the License. You may obtain
 *    a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
 *
 *    THIS CODE IS PROVIDED ON AN *AS IS* BASIS, WITHOUT WARRANTIES OR
 *    CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING WITHOUT
 *    LIMITATION ANY IMPLIED WARRANTIES OR CONDITIONS OF TITLE, FITNESS
 *    FOR A PARTICULAR PURPOSE, MERCHANTABILITY OR NON-INFRINGEMENT.
 *
 *    See the Apache Version 2.0 License for specific language governing
 *    permissions and limitations under the License.
 *
 *    Microsoft would like to thank the following companies for their review and
 *    assistance with these files: Intel Corporation, Mellanox Technologies Ltd,
 *    Dell Products, L.P., Facebook, Inc., Marvell International Ltd.
 *
 * @file    saiobject.h
 *
 * @brief   This module defines SAI APIs for bulk retrieval for each object-type
 */

#if !defined (__SAIOBJECT_H_)
#define __SAIOBJECT_H_

#include <saitypes.h>
#include <saifdb.h>
#include <saimcastfdb.h>
#include <sail2mc.h>
#include <saiipmc.h>
#include <saineighbor.h>
#include <sairoute.h>
#include <saimpls.h>
#include <sainat.h>

/**
 * @defgroup SAIOBJECT SAI - Object API definitions.
 *
 * @{
 */

/**
 * @extraparam sai_object_type_t object_type
 */
typedef union _sai_object_key_entry_t
{
    /**
     * @brief Key is object ID.
     *
     * @validonly sai_metadata_is_object_type_oid(object_type) == true
     */
    sai_object_id_t           object_id;

    /** @validonly object_type == SAI_OBJECT_TYPE_FDB_ENTRY */
    sai_fdb_entry_t           fdb_entry;

    /** @validonly object_type == SAI_OBJECT_TYPE_NEIGHBOR_ENTRY */
    sai_neighbor_entry_t      neighbor_entry;

    /** @validonly object_type == SAI_OBJECT_TYPE_ROUTE_ENTRY */
    sai_route_entry_t         route_entry;

    /** @validonly object_type == SAI_OBJECT_TYPE_MCAST_FDB_ENTRY */
    sai_mcast_fdb_entry_t     mcast_fdb_entry;

    /** @validonly object_type == SAI_OBJECT_TYPE_L2MC_ENTRY */
    sai_l2mc_entry_t          l2mc_entry;

    /** @validonly object_type == SAI_OBJECT_TYPE_IPMC_ENTRY */
    sai_ipmc_entry_t          ipmc_entry;

    /** @validonly object_type == SAI_OBJECT_TYPE_INSEG_ENTRY */
    sai_inseg_entry_t         inseg_entry;

    /** @validonly object_type == SAI_OBJECT_TYPE_NAT_ENTRY */
    sai_nat_entry_t           nat_entry;

} sai_object_key_entry_t;

/**
 * @brief Structure for bulk retrieval of object ids, attribute and values for
 * each object-type. Key will be used in case of object-types not having
 * object-ids.
 *
 * @extraparam sai_object_type_t object_type
 */
typedef struct _sai_object_key_t
{
    /** @passparam object_type */
    sai_object_key_entry_t key;

} sai_object_key_t;

/**
 * @brief Structure for attribute capabilities per operation
 */
typedef struct _sai_attr_capability_t
{
    /**
     * @brief Create is implemented
     */
    bool create_implemented;

    /**
     * @brief Set is implemented
     */
    bool set_implemented;

    /**
     * @brief Get is implemented
     */
    bool get_implemented;
} sai_attr_capability_t;

/**
 * @brief Get maximum number of attributes for an object type
 *
 * @param[in] switch_id SAI Switch object id
 * @param[in] object_type SAI object type
 * @param[out] count Maximum number of attribute for an object type
 *
 * @return #SAI_STATUS_SUCCESS on success, failure status code on error
 */
sai_status_t sai_get_maximum_attribute_count(
        _In_ sai_object_id_t switch_id,
        _In_ sai_object_type_t object_type,
        _Out_ uint32_t *count);

/**
 * @brief Get the number of objects present in SAI. Deprecated for backward compatibility.
 *
 * @param[in] switch_id SAI Switch object id
 * @param[in] object_type SAI object type
 * @param[out] count Number of objects in SAI
 *
 * @return #SAI_STATUS_SUCCESS on success, failure status code on error
 */
sai_status_t sai_get_object_count(
        _In_ sai_object_id_t switch_id,
        _In_ sai_object_type_t object_type,
        _Out_ uint32_t *count);

/**
 * @brief Get the number of and list of object keys present in SAI if enough large
 * list provided, otherwise get the number of object keys only.
 *
 * @param[in] switch_id SAI Switch object id
 * @param[in] object_type SAI object type
 * @param[inout] object_count Number of objects in SAI
 * @param[inout] object_list List of SAI objects or keys
 *
 * @return #SAI_STATUS_SUCCESS on success, #SAI_STATUS_BUFFER_OVERFLOW if list size insufficient, failure status code on error
 */
sai_status_t sai_get_object_key(
        _In_ sai_object_id_t switch_id,
        _In_ sai_object_type_t object_type,
        _Inout_ uint32_t *object_count,
        _Inout_ sai_object_key_t *object_list);

/**
 * @brief Get the bulk list of valid attributes for a given list of
 * object keys.
 *
 * Only valid attributes for an object are returned.
 *
 * @param[in] switch_id SAI Switch object id
 * @param[in] object_type SAI object type
 * @param[in] object_count Number of objects
 * @param[in] object_key List of object keys
 * @param[inout] attr_count List of attr_count. Caller passes the number
 *    of attribute allocated in. Callee returns with the actual
 *    number of attributes filled in. If the count is less than
 *    needed, callee fills with the needed count and do not fill
 *    the attributes. Callee also set the corresponding status to
 *    #SAI_STATUS_BUFFER_OVERFLOW.
 *
 * @param[inout] attr_list List of attributes for every object. Caller is
 *    responsible for allocating and freeing buffer for the attributes.
 *    For list based attribute, e.g., s32list, objlist, callee should
 *    assume the caller has not allocated the memory for the list and
 *    should only to fill the count but not list. Then, caller
 *    can use corresponding get_attribute to get the list.
 *
 * @param[inout] object_statuses Status for each object. If the object does
 *    not exist, callee sets the corresponding status to #SAI_STATUS_INVALID_OBJECT_ID.
 *    If the allocated attribute count is not large enough,
 *    set the status to #SAI_STATUS_BUFFER_OVERFLOW.
 *
 * @return #SAI_STATUS_SUCCESS on success, failure status code on error
 */
sai_status_t sai_bulk_get_attribute(
        _In_ sai_object_id_t switch_id,
        _In_ sai_object_type_t object_type,
        _In_ uint32_t object_count,
        _In_ const sai_object_key_t *object_key,
        _Inout_ uint32_t *attr_count,
        _Inout_ sai_attribute_t **attr_list,
        _Inout_ sai_status_t *object_statuses);

/**
 * @brief Query attribute capability
 *
 * @param[in] switch_id SAI Switch object id
 * @param[in] object_type SAI object type
 * @param[in] attr_id SAI attribute ID
 * @param[out] attr_capability Capability per operation
 *
 * @return #SAI_STATUS_SUCCESS on success, failure status code on error
 */
sai_status_t sai_query_attribute_capability(
        _In_ sai_object_id_t switch_id,
        _In_ sai_object_type_t object_type,
        _In_ sai_attr_id_t attr_id,
        _Out_ sai_attr_capability_t *attr_capability);

/**
 * @brief Query an enum attribute (enum or enum list) list of implemented enum values
 *
 * @param[in] switch_id SAI Switch object id
 * @param[in] object_type SAI object type
 * @param[in] attr_id SAI attribute ID
 * @param[inout] enum_values_capability List of implemented enum values
 *
 * @return #SAI_STATUS_SUCCESS on success, #SAI_STATUS_BUFFER_OVERFLOW if list size insufficient, failure status code on error
 */
sai_status_t sai_query_attribute_enum_values_capability(
        _In_ sai_object_id_t switch_id,
        _In_ sai_object_type_t object_type,
        _In_ sai_attr_id_t attr_id,
        _Inout_ sai_s32_list_t *enum_values_capability);

/**
 * @}
 */
#endif /** __SAIOBJECT_H_ */


#!/usr/bin/env python
# -*- coding: utf-8 -*-
#!/usr/bin/env python2
# This file is part of the OpenMV project.
#
# Copyright (c) 2013-2019 Ibrahim Abdelkader <iabdalkader@openmv.io>
# Copyright (c) 2013-2019 Kwabena W. Agyeman <kwagyeman@openmv.io>
#
# This work is licensed under the MIT license, see the file LICENSE for details.
#
# This script generates RGB to RGB lookup table.

import sys
sys.stdout.write("#include <stdint.h>\n")

sys.stdout.write("const uint8_t rb528_table[32] = {\n")
for i in range(32):
    if not (i % 8):
        sys.stdout.write("    ")
    sys.stdout.write("%3d" % (((i * 255) + 15.5) // 31))
    if (i + 1) % 8:
        sys.stdout.write(", ")
    elif i != 31:
        sys.stdout.write(",\n")
    else:
        sys.stdout.write("\n};\n")

sys.stdout.write("const uint8_t g628_table[64] = {\n")
for i in range(64):
    if not (i % 8):
        sys.stdout.write("    ")
    sys.stdout.write("%3d" % (((i * 255) + 31.5) // 63))
    if (i + 1) % 8:
        sys.stdout.write(", ")
    elif i != 63:
        sys.stdout.write(",\n")
    else:
        sys.stdout.write("\n};\n")

sys.stdout.write("const uint8_t rb825_table[256] = {\n")
for i in range(256):
    if not (i % 8):
        sys.stdout.write("    ")
    sys.stdout.write("%3d" % (((i * 31) + 127.5) // 255))
    if (i + 1) % 8:
        sys.stdout.write(", ")
    elif i != 255:
        sys.stdout.write(",\n")
    else:
        sys.stdout.write("\n};\n")

sys.stdout.write("const uint8_t g826_table[256] = {\n")
for i in range(256):
    if not (i % 8):
        sys.stdout.write("    ")
    sys.stdout.write("%3d" % (((i * 63) + 127.5) // 255))
    if (i + 1) % 8:
        sys.stdout.write(", ")
    elif i != 255:
        sys.stdout.write(",\n")
    else:
        sys.stdout.write("\n};\n")


//
// Created by Fabrice Aneche on 06/01/14.
// Copyright (c) 2014 Dailymotion. All rights reserved.
//

#import <Foundation/Foundation.h>

@interface NSData (ImageContentType)

/**
 *  Compute the content type for an image data
 *
 *  @param data the input data
 *
 *  @return the content type as string (i.e. image/jpeg, image/gif)
 */
+ (NSString *)sd_contentTypeForImageData:(NSData *)data;

@end

@interface NSData (ImageContentTypeDeprecated)

+ (NSString *)contentTypeForImageData:(NSData *)data __deprecated_msg("Use `sd_contentTypeForImageData:`");

@end


<?xml version="1.0" encoding="UTF-8"?>
<message>
    <name>RPLI02</name>
    <description>Request/Receipt of Patient Selection Display List - Response</description>
    <segments>
        <segment>MSH</segment>
        <segment>MSA</segment>
        <group maxOccurs="unbounded">
            <segment>PRD</segment>
            <segment minOccurs="0" maxOccurs="unbounded">CTD</segment>
        </group>
        <segment minOccurs="0" maxOccurs="unbounded">NTE</segment>
        <segment minOccurs="0" maxOccurs="unbounded">DSP</segment>
        <segment minOccurs="0">DSC</segment>
    </segments>
</message>


/*
 * Copyright (C)2005-2012 Haxe Foundation
 *
 * Permission is hereby granted, free of charge, to any person obtaining a
 * copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation
 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
 * and/or sell copies of the Software, and to permit persons to whom the
 * Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
 * DEALINGS IN THE SOFTWARE.
 */

readdir = $loader.loadprim("std@sys_read_dir",1);
command = $loader.loadprim("std@sys_command",1);

exec = function(cmd) {
	$print(cmd,"\n");
	var ecode = command(cmd);
	if( ecode != 0 )
		$throw("Error "+ecode+" : aborted");
}

makedoc = function(file) {
	exec("nekoc -o ../www/libs -doc ../"+file);
}

files = $array(
	"vm/builtins.c",
);

var i = 0;
var l = $asize(files);
while i < l {
	makedoc(files[i]);
	i = i + 1;
}

var libs = readdir("../libs");
while( libs != null ) {
	var l = libs[0];
	var k = try readdir("../libs/"+l) catch _ { null };
	if( l == "mod_tora" ) k = null;
	while( k != null ) {
		var f = k[0];
		var len = $ssize(f);
		if( $ssub(f,len-2,2) == ".c" )
			makedoc("libs/"+l+"/"+f);
		k = k[1];
	}
	libs = libs[1];
}


        <button type="button" class="close" data-dismiss="modal"
        aria-hidden="true">
          x
        </button>

{{title}}

            {{description}}

        <button class="btn" data-dismiss="modal" aria-hidden="true">
          Cancel
        </button>
        <button id="{{modal_id}}-confirm" class="btn btn-primary"
        onclick="{% if command %}$('#{{modal_id}}-confirm').prop('disabled', true); makeAjaxCall('/ajax/command/?command={{command}}{{ctx}}', '', commandCallback('#{{modal_id}}')){% else %}{{ onclick }}{% endif %}">
          Confirm
        </button>


// Copyright 2016 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

// White-box tests for transport.go (in package http instead of http_test).

package http

import (
	"bytes"
	"crypto/tls"
	"errors"
	"io"
	"io/ioutil"
	"net"
	"net/http/internal"
	"strings"
	"testing"
)

// Issue 15446: incorrect wrapping of errors when server closes an idle connection.
func TestTransportPersistConnReadLoopEOF(t *testing.T) {
	ln := newLocalListener(t)
	defer ln.Close()

	connc := make(chan net.Conn, 1)
	go func() {
		defer close(connc)
		c, err := ln.Accept()
		if err != nil {
			t.Error(err)
			return
		}
		connc <- c
	}()

	tr := new(Transport)
	req, _ := NewRequest("GET", "http://"+ln.Addr().String(), nil)
	req = req.WithT(t)
	treq := &transportRequest{Request: req}
	cm := connectMethod{targetScheme: "http", targetAddr: ln.Addr().String()}
	pc, err := tr.getConn(treq, cm)
	if err != nil {
		t.Fatal(err)
	}
	defer pc.close(errors.New("test over"))

	conn := <-connc
	if conn == nil {
		// Already called t.Error in the accept goroutine.
		return
	}
	conn.Close() // simulate the server hanging up on the client

	_, err = pc.roundTrip(treq)
	if !isTransportReadFromServerError(err) && err != errServerClosedIdle {
		t.Errorf("roundTrip = %#v, %v; want errServerClosedIdle or transportReadFromServerError", err, err)
	}

	<-pc.closech
	err = pc.closed
	if !isTransportReadFromServerError(err) && err != errServerClosedIdle {
		t.Errorf("pc.closed = %#v, %v; want errServerClosedIdle or transportReadFromServerError", err, err)
	}
}

func isTransportReadFromServerError(err error) bool {
	_, ok := err.(transportReadFromServerError)
	return ok
}

func newLocalListener(t *testing.T) net.Listener {
	ln, err := net.Listen("tcp", "127.0.0.1:0")
	if err != nil {
		ln, err = net.Listen("tcp6", "[::1]:0")
	}
	if err != nil {
		t.Fatal(err)
	}
	return ln
}

func dummyRequest(method string) *Request {
	req, err := NewRequest(method, "http://fake.tld/", nil)
	if err != nil {
		panic(err)
	}
	return req
}
func dummyRequestWithBody(method string) *Request {
	req, err := NewRequest(method, "http://fake.tld/", strings.NewReader("foo"))
	if err != nil {
		panic(err)
	}
	return req
}

func dummyRequestWithBodyNoGetBody(method string) *Request {
	req := dummyRequestWithBody(method)
	req.GetBody = nil
	return req
}

// issue22091Error acts like a golang.org/x/net/http2.ErrNoCachedConn.
type issue22091Error struct{}

func (issue22091Error) IsHTTP2NoCachedConnError() {}
func (issue22091Error) Error() string             { return "issue22091Error" }

func TestTransportShouldRetryRequest(t *testing.T) {
	tests := []struct {
		pc  *persistConn
		req *Request

		err  error
		want bool
	}{
		0: {
			pc:   &persistConn{reused: false},
			req:  dummyRequest("POST"),
			err:  nothingWrittenError{},
			want: false,
		},
		1: {
			pc:   &persistConn{reused: true},
			req:  dummyRequest("POST"),
			err:  nothingWrittenError{},
			want: true,
		},
		2: {
			pc:   &persistConn{reused: true},
			req:  dummyRequest("POST"),
			err:  http2ErrNoCachedConn,
			want: true,
		},
		3: {
			pc:   nil,
			req:  nil,
			err:  issue22091Error{}, // like an external http2ErrNoCachedConn
			want: true,
		},
		4: {
			pc:   &persistConn{reused: true},
			req:  dummyRequest("POST"),
			err:  errMissingHost,
			want: false,
		},
		5: {
			pc:   &persistConn{reused: true},
			req:  dummyRequest("POST"),
			err:  transportReadFromServerError{},
			want: false,
		},
		6: {
			pc:   &persistConn{reused: true},
			req:  dummyRequest("GET"),
			err:  transportReadFromServerError{},
			want: true,
		},
		7: {
			pc:   &persistConn{reused: true},
			req:  dummyRequest("GET"),
			err:  errServerClosedIdle,
			want: true,
		},
		8: {
			pc:   &persistConn{reused: true},
			req:  dummyRequestWithBody("POST"),
			err:  nothingWrittenError{},
			want: true,
		},
		9: {
			pc:   &persistConn{reused: true},
			req:  dummyRequestWithBodyNoGetBody("POST"),
			err:  nothingWrittenError{},
			want: false,
		},
	}
	for i, tt := range tests {
		got := tt.pc.shouldRetryRequest(tt.req, tt.err)
		if got != tt.want {
			t.Errorf("%d. shouldRetryRequest = %v; want %v", i, got, tt.want)
		}
	}
}

type roundTripFunc func(r *Request) (*Response, error)

func (f roundTripFunc) RoundTrip(r *Request) (*Response, error) {
	return f(r)
}

// Issue 25009
func TestTransportBodyAltRewind(t *testing.T) {
	cert, err := tls.X509KeyPair(internal.LocalhostCert, internal.LocalhostKey)
	if err != nil {
		t.Fatal(err)
	}
	ln := newLocalListener(t)
	defer ln.Close()

	go func() {
		tln := tls.NewListener(ln, &tls.Config{
			NextProtos:   []string{"foo"},
			Certificates: []tls.Certificate{cert},
		})
		for i := 0; i < 2; i++ {
			sc, err := tln.Accept()
			if err != nil {
				t.Error(err)
				return
			}
			if err := sc.(*tls.Conn).Handshake(); err != nil {
				t.Error(err)
				return
			}
			sc.Close()
		}
	}()

	addr := ln.Addr().String()
	req, _ := NewRequest("POST", "https://example.org/", bytes.NewBufferString("request"))
	roundTripped := false
	tr := &Transport{
		DisableKeepAlives: true,
		TLSNextProto: map[string]func(string, *tls.Conn) RoundTripper{
			"foo": func(authority string, c *tls.Conn) RoundTripper {
				return roundTripFunc(func(r *Request) (*Response, error) {
					n, _ := io.Copy(ioutil.Discard, r.Body)
					if n == 0 {
						t.Error("body length is zero")
					}
					if roundTripped {
						return &Response{
							Body:       NoBody,
							StatusCode: 200,
						}, nil
					}
					roundTripped = true
					return nil, http2noCachedConnError{}
				})
			},
		},
		DialTLS: func(_, _ string) (net.Conn, error) {
			tc, err := tls.Dial("tcp", addr, &tls.Config{
				InsecureSkipVerify: true,
				NextProtos:         []string{"foo"},
			})
			if err != nil {
				return nil, err
			}
			if err := tc.Handshake(); err != nil {
				return nil, err
			}
			return tc, nil
		},
	}
	c := &Client{Transport: tr}
	_, err = c.Do(req)
	if err != nil {
		t.Error(err)
	}
}