text:
namespace libspirv {

namespace {

uint32_t GetSizeTBitWidth(const ValidationState_t& _) {
  if (_.addressing_model() == SpvAddressingModelPhysical32) return 32;

  if (_.addressing_model() == SpvAddressingModelPhysical64) return 64;

  return 0;
}

}  // anonymous namespace

// Validates correctness of ExtInst instructions.
spv_result_t ExtInstPass(ValidationState_t& _,
                         const spv_parsed_instruction_t* inst) {
  const SpvOp opcode = static_cast<SpvOp>(inst->opcode);
  const uint32_t result_type = inst->type_id;
  const uint32_t num_operands = inst->num_operands;

  if (opcode != SpvOpExtInst) return SPV_SUCCESS;

  const uint32_t ext_inst_set = inst->words[3];
  const uint32_t ext_inst_index = inst->words[4];
  const spv_ext_inst_type_t ext_inst_type =
      spv_ext_inst_type_t(inst->ext_inst_type);

  auto ext_inst_name = [&_, ext_inst_set, ext_inst_type, ext_inst_index]() {
    spv_ext_inst_desc desc = nullptr;
    if (_.grammar().lookupExtInst(ext_inst_type, ext_inst_index, &desc) !=
            SPV_SUCCESS ||
        !desc) {
      return std::string("Unknown ExtInst");
    }

    auto* import_inst = _.FindDef(ext_inst_set);
    assert(import_inst);

    std::ostringstream ss;
    ss << reinterpret_cast<const char*>(import_inst->words().data() + 2);
    ss << " ";
    ss << desc->name;

    return ss.str();
  };

  if (ext_inst_type == SPV_EXT_INST_TYPE_GLSL_STD_450) {
    const GLSLstd450 ext_inst_key = GLSLstd450(ext_inst_index);
    switch (ext_inst_key) {
      case GLSLstd450Round:
      case GLSLstd450RoundEven:
      case GLSLstd450FAbs:
      case GLSLstd450Trunc:
      case GLSLstd450FSign:
      case GLSLstd450Floor:
      case GLSLstd450Ceil:
      case GLSLstd450Fract:
      case GLSLstd450Sqrt:
      case GLSLstd450InverseSqrt:
      case GLSLstd450FMin:
      case GLSLstd450FMax:
      case GLSLstd450FClamp:
      case GLSLstd450FMix:
      case GLSLstd450Step:
      case GLSLstd450SmoothStep:
      case GLSLstd450Fma:
      case GLSLstd450Normalize:
      case GLSLstd450FaceForward:
      case GLSLstd450Reflect:
      case GLSLstd450NMin:
      case GLSLstd450NMax:
      case GLSLstd450NClamp: {
        if (!_.IsFloatScalarOrVectorType(result_type)) {
          return _.diag(SPV_ERROR_INVALID_DATA)
                 << ext_inst_name() << ": "
                 << "expected Result Type to be a float scalar or vector type";
        }

        for (uint32_t operand_index = 4; operand_index < num_operands;
             ++operand_index) {
          const uint32_t operand_type = _.GetOperandTypeId(inst, operand_index);
          if (result_type != operand_type) {
            return _.diag(SPV_ERROR_INVALID_DATA)
                   << ext_inst_name() << ": "
                   << "expected types of all operands to be equal to Result "
                      "Type";
          }
        }
        break;
      }

      case GLSLstd450SAbs:
      case GLSLstd450SSign:
      case GLSLstd450UMin:
      case GLSLstd450SMin:
      case GLSLstd450UMax:
      case GLSLstd450SMax:
      case GLSLstd450UClamp:
      case GLSLstd450SClamp:
      case GLSLstd450FindILsb:
      case GLSLstd450FindUMsb:
      case GLSLstd450FindSMsb: {
        if (!_.IsIntScalarOrVectorType(result_type)) {
          return _.diag(SPV_ERROR_INVALID_DATA)
                 << ext_inst_name() << ": "
                 << "expected Result Type to be an int scalar or vector type";
        }

        const uint32_t result_type_bit_width = _.GetBitWidth(result_type);
        const uint32_t result_type_dimension = _.GetDimension(result_type);

        for (uint32_t operand_index = 4; operand_index < num_operands;
             ++operand_index) {
          const uint32_t operand_type = _.GetOperandTypeId(inst, operand_index);
          if (!_.IsIntScalarOrVectorType(operand_type)) {
            return _.diag(SPV_ERROR_INVALID_DATA)
                   << ext_inst_name() << ": "
                   << "expected all operands to be int scalars or vectors";
          }

          if (result_type_dimension != _.GetDimension(operand_type)) {
            return _.diag(SPV_ERROR_INVALID_DATA)
                   << ext_inst_name() << ": "
                   << "expected all operands to have the same dimension as "
                   << "Result Type";
          }

          if (result_type_bit_width != _.GetBitWidth(operand_type)) {
            return _.diag(SPV_ERROR_INVALID_DATA)
                   << ext_inst_name() << ": "
                   << "expected all operands to have the same bit width as "
                   << "Result Type";
          }

          if (ext_inst_key == GLSLstd450FindUMsb ||
              ext_inst_key == GLSLstd450FindSMsb) {
            if (result_type_bit_width != 32) {
              return _.diag(SPV_ERROR_INVALID_DATA)
                     << ext_inst_name() << ": "
                     << "this instruction is currently limited to 32-bit width "
                     << "components";
            }
          }
        }
        break;
      }

      case GLSLstd450Radians:
      case GLSLstd450Degrees:
      case GLSLstd450Sin:
      case GLSLstd450Cos:
      case GLSLstd450Tan:
      case GLSLstd450Asin:
      case GLSLstd450Acos:
      case GLSLstd450Atan:
      case GLSLstd450Sinh:
      case GLSLstd450Cosh:
      case GLSLstd450Tanh:
      case GLSLstd450Asinh:
      case GLSLstd450Acosh:
      case GLSLstd450Atanh:
      case GLSLstd450Exp:
      case GLSLstd450Exp2:
      case GLSLstd450Log:
      case GLSLstd450Log2:
      case GLSLstd450Atan2:
      case GLSLstd450Pow: {
        if (!_.IsFloatScalarOrVectorType(result_type)) {
          return _.diag(SPV_ERROR_INVALID_DATA)
                 << ext_inst_name() << ": "
                 << "expected Result Type to be a 16 or 32-bit scalar or "
                    "vector float type";
        }

        const uint32_t result_type_bit_width = _.GetBitWidth(result_type);
        if (result_type_bit_width != 16 && result_type_bit_width != 32) {
          return _.diag(SPV_ERROR_INVALID_DATA)
                 << ext_inst_name() << ": "
                 << "expected Result Type to be a 16 or 32-bit scalar or "
                    "vector float type";
        }

        for (uint32_t operand_index = 4; operand_index < num_operands;
             ++operand_index) {
          const uint32_t operand_type = _.GetOperandTypeId(inst, operand_index);
          if (result_type != operand_type) {
            return _.diag(SPV_ERROR_INVALID_DATA)
                   << ext_inst_name() << ": "
                   << "expected types of all operands to be equal to Result "
                      "Type";
          }
        }
        break;
      }

      case GLSLstd450Determinant: {
        const uint32_t x_type = _.GetOperandTypeId(inst, 4);
        uint32_t num_rows = 0;
        uint32_t num_cols = 0;
        uint32_t col_type = 0;
        uint32_t component_type = 0;
        if (!_.GetMatrixTypeInfo(x_type, &num_rows, &num_cols, &col_type,
                                 &component_type) ||
            num_rows != num_cols) {
          return _.diag(SPV_ERROR_INVALID_DATA)
                 << ext_inst_name() << ": "
                 << "expected operand X to be a square matrix";
        }

        if (result_type != component_type) {
          return _.diag(SPV_ERROR_INVALID_DATA)
                 << ext_inst_name() << ": "
                 << "expected operand X component type to be equal to "
                 << "Result Type";
        }
        break;
      }

      case GLSLstd450MatrixInverse: {
        uint32_t num_rows = 0;
        uint32_t num_cols = 0;
        uint32_t col_type = 0;
        uint32_t component_type = 0;
        if (!_.GetMatrixTypeInfo(result_type, &num_rows, &num_cols, &col_type,
                                 &component_type) ||
            num_rows != num_cols) {
          return _.diag(SPV_ERROR_INVALID_DATA)
                 << ext_inst_name() << ": "
                 << "expected Result Type to be a square matrix";
        }

        const uint32_t x_type = _.GetOperandTypeId(inst, 4);
        if (result_type != x_type) {
          return _.diag(SPV_ERROR_INVALID_DATA)
                 << ext_inst_name() << ": "
                 << "expected operand X type to be equal to Result Type";
        }
        break;
      }

      case GLSLstd450Modf: {
        if (!_.IsFloatScalarOrVectorType(result_type)) {
          return _.diag(SPV_ERROR_INVALID_DATA)
                 << ext_inst_name() << ": "
                 << "expected Result Type to be a scalar or vector float type";
        }

        const uint32_t x_type = _.GetOperandTypeId(inst, 4);
        const uint32_t i_type = _.GetOperandTypeId(inst, 5);

        if (x_type != result_type) {
          return _.diag(SPV_ERROR_INVALID_DATA)
                 << ext_inst_name() << ": "
                 << "expected operand X type to be equal to Result Type";
        }

        uint32_t i_storage_class = 0;
        uint32_t i_data_type = 0;
        if (!_.GetPointerTypeInfo(i_type, &i_data_type, &i_storage_class)) {
          return _.diag(SPV_ERROR_INVALID_DATA)
                 << ext_inst_name() << ": "
                 << "expected operand I to be a pointer";
        }

        if (i_data_type != result_type) {
          return _.diag(SPV_ERROR_INVALID_DATA)
                 << ext_inst_name() << ": "
                 << "expected operand I data type to be equal to Result Type";
        }

        break;
      }

      case GLSLstd450ModfStruct: {
        std::vector<uint32_t> result_types;
        if (!_.GetStructMemberTypes(result_type, &result_types) ||
            result_types.size() != 2 ||
            !_.IsFloatScalarOrVectorType(result_types[0]) ||
            result_types[1] != result_types[0]) {
          return _.diag(SPV_ERROR_INVALID_DATA)
                 << ext_inst_name() << ": "
                 << "expected Result Type to be a struct with two identical "
                 << "scalar or vector float type members";
        }

        const uint32_t x_type = _.GetOperandTypeId(inst, 4);
        if (x_type != result_types[0]) {
          return _.diag(SPV_ERROR_INVALID_DATA)
                 << ext_inst_name() << ": "
                 << "expected operand X type to be equal to members of "
                 << "Result Type struct";
        }
        break;
      }

      case GLSLstd450Frexp: {
        if (!_.IsFloatScalarOrVectorType(result_type)) {
          return _.diag(SPV_ERROR_INVALID_DATA)
                 << ext_inst_name() << ": "
                 << "expected Result Type to be a scalar or vector float type";
        }

        const uint32_t x_type = _.GetOperandTypeId(inst, 4);
        const uint32_t exp_type = _.GetOperandTypeId(inst, 5);

        if (x_type != result_type) {
          return _.diag(SPV_ERROR_INVALID_DATA)
                 << ext_inst_name() << ": "
                 << "expected operand X type to be equal to Result Type";
        }

        uint32_t exp_storage_class = 0;
        uint32_t exp_data_type = 0;
        if (!_.GetPointerTypeInfo(exp_type, &exp_data_type,
                                  &exp_storage_class)) {
          return _.diag(SPV_ERROR_INVALID_DATA)
                 << ext_inst_name() << ": "
                 << "expected operand Exp to be a pointer";
        }

        if (!_.IsIntScalarOrVectorType(exp_data_type) ||
            _.GetBitWidth(exp_data_type) != 32) {
          return _.diag(SPV_ERROR_INVALID_DATA)
                 << ext_inst_name() << ": "
                 << "expected operand Exp data type to be a 32-bit int scalar "
                 << "or vector type";
        }

        if (_.GetDimension(result_type) != _.GetDimension(exp_data_type)) {
          return _.diag(SPV_ERROR_INVALID_DATA)
                 << ext_inst_name() << ": "
                 << "expected operand Exp data type to have the same component "
                 << "number as Result Type";
        }

        break;
      }

      case GLSLstd450Ldexp: {
        if (!_.IsFloatScalarOrVectorType(result_type)) {
          return _.diag(SPV_ERROR_INVALID_DATA)
                 << ext_inst_name() << ": "
                 << "expected Result Type to be a scalar or vector float type";
        }

        const uint32_t x_type = _.GetOperandTypeId(inst, 4);
        const uint32_t exp_type = _.GetOperandTypeId(inst, 5);

        if (x_type != result_type) {
          return _.diag(SPV_ERROR_INVALID_DATA)
                 << ext_inst_name() << ": "
                 << "expected operand X type to be equal to Result Type";
        }

        if (!_.IsIntScalarOrVectorType(exp_type)) {
          return _.diag(SPV_ERROR_INVALID_DATA)
                 << ext_inst_name() << ": "
                 << "expected operand Exp to be a 32-bit int scalar "
                 << "or vector type";
        }

        if (_.GetDimension(result_type) != _.GetDimension(exp_type)) {
          return _.diag(SPV_ERROR_INVALID_DATA)
                 << ext_inst_name() << ": "
                 << "expected operand Exp to have the same component "
                 << "number as Result Type";
        }

        break;
      }

      case GLSLstd450FrexpStruct: {
        std::vector<uint32_t> result_types;
        if (!_.GetStructMemberTypes(result_type, &result_types) ||
            result_types.size() != 2 ||
            !_.IsFloatScalarOrVectorType(result_types[0]) ||
            !_.IsIntScalarOrVectorType(result_types[1]) ||
            _.GetBitWidth(result_types[1]) != 32 ||
            _.GetDimension(result_types[0]) !=
                _.GetDimension(result_types[1])) {
          return _.diag(SPV_ERROR_INVALID_DATA)
                 << ext_inst_name() << ": "
                 << "expected Result Type to be a struct with two members, "
                 << "first member a float scalar or vector, second member "
                 << "a 32-bit int scalar or vector with the same number of "
                 << "components as the first member";
        }

        const uint32_t x_type = _.GetOperandTypeId(inst, 4);
        if (x_type != result_types[0]) {
          return _.diag(SPV_ERROR_INVALID_DATA)
                 << ext_inst_name() << ": "
                 << "expected operand X type to be equal to the first member "
                 << "of Result Type struct";
        }
        break;
      }

      case GLSLstd450PackSnorm4x8:
      case GLSLstd450PackUnorm4x8: {
        if (!_.IsIntScalarType(result_type) ||
            _.GetBitWidth(result_type) != 32) {
          return _.diag(SPV_ERROR_INVALID_DATA)
                 << ext_inst_name() << ": "
                 << "expected Result Type to be 32-bit int scalar type";
        }

        const uint32_t v_type = _.GetOperandTypeId(inst, 4);
        if (!_.IsFloatVectorType(v_type) || _.GetDimension(v_type) != 4 ||
            _.GetBitWidth(v_type) != 32) {
          return _.diag(SPV_ERROR_INVALID_DATA)
                 << ext_inst_name() << ": "
                 << "expected operand V to be a 32-bit float vector of size 4";
        }
        break;
      }

      case GLSLstd450PackSnorm2x16:
      case GLSLstd450PackUnorm2x16:
      case GLSLstd450PackHalf2x16: {
        if (!_.IsIntScalarType(result_type) ||
            _.GetBitWidth(result_type) != 32) {
          return _.diag(SPV_ERROR_INVALID_DATA)
                 << ext_inst_name() << ": "
                 << "expected Result Type to be 32-bit int scalar type";
        }

        const uint32_t v_type = _.GetOperandTypeId(inst, 4);
        if (!_.IsFloatVectorType(v_type) || _.GetDimension(v_type) != 2 ||
            _.GetBitWidth(v_type) != 32) {
          return _.diag(SPV_ERROR_INVALID_DATA)
                 << ext_inst_name() << ": "
                 << "expected operand V to be a 32-bit float vector of size 2";
        }
        break;
      }

      case GLSLstd450PackDouble2x32: {
        if (!_.IsFloatScalarType(result_type) ||
            _.GetBitWidth(result_type) != 64) {
          return _.diag(SPV_ERROR_INVALID_DATA)
                 << ext_inst_name() << ": "
                 << "expected Result Type to be 64-bit float scalar type";
        }

        const uint32_t v_type = _.GetOperandTypeId(inst, 4);
        if (!_.IsIntVectorType(v_type) || _.GetDimension(v_type) != 2 ||
            _.GetBitWidth(v_type) != 32) {
          return _.diag(SPV_ERROR_INVALID_DATA)
                 << ext_inst_name() << ": "
                 << "expected operand V to be a 32-bit int vector of size 2";
        }
        break;
      }

      case GLSLstd450UnpackSnorm4x8:
      case GLSLstd450UnpackUnorm4x8: {
        if (!_.IsFloatVectorType(result_type) ||
            _.GetDimension(result_type) != 4 ||
            _.GetBitWidth(result_type) != 32) {
          return _.diag(SPV_ERROR_INVALID_DATA)
                 << ext_inst_name() << ": "
                 << "expected Result Type to be a 32-bit float vector of size "
                    "4";
        }

        const uint32_t v_type = _.GetOperandTypeId(inst, 4);
        if (!_.IsIntScalarType(v_type) || _.GetBitWidth(v_type) != 32) {
          return _.diag(SPV_ERROR_INVALID_DATA)
                 << ext_inst_name() << ": "
                 << "expected operand P to be a 32-bit int scalar";
        }
        break;
      }

      case GLSLstd450UnpackSnorm2x16:
      case GLSLstd450UnpackUnorm2x16:
      case GLSLstd450UnpackHalf2x16: {
        if (!_.IsFloatVectorType(result_type) ||
            _.GetDimension(result_type) != 2 ||
            _.GetBitWidth(result_type) != 32) {
          return _.diag(SPV_ERROR_INVALID_DATA)
                 << ext_inst_name() << ": "
                 << "expected Result Type to be a 32-bit float vector of size "
                    "2";
        }

        const uint32_t v_type = _.GetOperandTypeId(inst, 4);
        if (!_.IsIntScalarType(v_type) || _.GetBitWidth(v_type) != 32) {
          return _.diag(SPV_ERROR_INVALID_DATA)
                 << ext_inst_name() << ": "
                 << "expected operand P to be a 32-bit int scalar";
        }
        break;
      }

      case GLSLstd450UnpackDouble2x32: {
        if (!_.IsIntVectorType(result_type) ||
            _.GetDimension(result_type) != 2 ||
            _.GetBitWidth(result_type) != 32) {
          return _.diag(SPV_ERROR_INVALID_DATA)
                 << ext_inst_name() << ": "
                 << "expected Result Type to be a 32-bit int vector of size "
                    "2";
        }

        const uint32_t v_type = _.GetOperandTypeId(inst, 4);
        if (!_.IsFloatScalarType(v_type) || _.GetBitWidth(v_type) != 64) {
          return _.diag(SPV_ERROR_INVALID_DATA)
                 << ext_inst_name() << ": "
                 << "expected operand V to be a 64-bit float scalar";
        }
        break;
      }

      case GLSLstd450Length: {
        if (!_.IsFloatScalarType(result_type)) {
          return _.diag(SPV_ERROR_INVALID_DATA)
                 << ext_inst_name() << ": "
                 << "expected Result Type to be a float scalar type";
        }

        const uint32_t x_type = _.GetOperandTypeId(inst, 4);
        if (!_.IsFloatScalarOrVectorType(x_type)) {
          return _.diag(SPV_ERROR_INVALID_DATA)
                 << ext_inst_name() << ": "
                 << "expected operand X to be of float scalar or vector type";
        }

        if (result_type != _.GetComponentType(x_type)) {
          return _.diag(SPV_ERROR_INVALID_DATA)
                 << ext_inst_name() << ": "
                 << "expected operand X component type to be equal to Result "
                    "Type";
        }
        break;
      }

      case GLSLstd450Distance: {
        if (!_.IsFloatScalarType(result_type)) {
          return _.diag(SPV_ERROR_INVALID_DATA)
                 << ext_inst_name() << ": "
                 << "expected Result Type to be a float scalar type";
        }

        const uint32_t p0_type = _.GetOperandTypeId(inst, 4);
        if (!_.IsFloatScalarOrVectorType(p0_type)) {
          return _.diag(SPV_ERROR_INVALID_DATA)
                 << ext_inst_name() << ": "
                 << "expected operand P0 to be of float scalar or vector type";
        }

        if (result_type != _.GetComponentType(p0_type)) {
          return _.diag(SPV_ERROR_INVALID_DATA)
                 << ext_inst_name() << ": "
                 << "expected operand P0 component type to be equal to "
                 << "Result Type";
        }

        const uint32_t p1_type = _.GetOperandTypeId(inst, 5);
        if (!_.IsFloatScalarOrVectorType(p1_type)) {
          return _.diag(SPV_ERROR_INVALID_DATA)
                 << ext_inst_name() << ": "
                 << "expected operand P1 to be of float scalar or vector type";
        }

        if (result_type != _.GetComponentType(p1_type)) {
          return _.diag(SPV_ERROR_INVALID_DATA)
                 << ext_inst_name() << ": "
                 << "expected operand P1 component type to be equal to "
                 << "Result Type";
        }

        if (_.GetDimension(p0_type) != _.GetDimension(p1_type)) {
          return _.diag(SPV_ERROR_INVALID_DATA)
                 << ext_inst_name() << ": "
                 << "expected operands P0 and P1 to have the same number of "
                 << "components";
        }
        break;
      }

      case GLSLstd450Cross: {
        if (!_.IsFloatVectorType(result_type)) {
          return _.diag(SPV_ERROR_INVALID_DATA)
                 << ext_inst_name() << ": "
                 << "expected Result Type to be a float vector type";
        }

        if (_.GetDimension(result_type) != 3) {
          return _.diag(SPV_ERROR_INVALID_DATA)
                 << ext_inst_name() << ": "
                 << "expected Result Type to have 3 components";
        }

        const uint32_t x_type = _.GetOperandTypeId(inst, 4);
        const uint32_t y_type = _.GetOperandTypeId(inst, 5);

        if (x_type != result_type) {
          return _.diag(SPV_ERROR_INVALID_DATA)
                 << ext_inst_name() << ": "
                 << "expected operand X type to be equal to Result Type";
        }

        if (y_type != result_type) {
          return _.diag(SPV_ERROR_INVALID_DATA)
                 << ext_inst_name() << ": "
                 << "expected operand Y type to be equal to Result Type";
        }
        break;
      }

      case GLSLstd450Refract: {
        if (!_.IsFloatScalarOrVectorType(result_type)) {
          return _.diag(SPV_ERROR_INVALID_DATA)
                 << ext_inst_name() << ": "
                 << "expected Result Type to be a float scalar or vector type";
        }

        const uint32_t i_type = _.GetOperandTypeId(inst, 4);
        const uint32_t n_type = _.GetOperandTypeId(inst, 5);
        const uint32_t eta_type = _.GetOperandTypeId(inst, 6);

        if (result_type != i_type) {
          return _.diag(SPV_ERROR_INVALID_DATA)
                 << ext_inst_name() << ": "
                 << "expected operand I to be of type equal to Result Type";
        }

        if (result_type != n_type) {
          return _.diag(SPV_ERROR_INVALID_DATA)
                 << ext_inst_name() << ": "
                 << "expected operand N to be of type equal to Result Type";
        }

        const uint32_t eta_type_bit_width = _.GetBitWidth(eta_type);
        if (!_.IsFloatScalarType(eta_type) ||
            (eta_type_bit_width != 16 && eta_type_bit_width != 32)) {
          return _.diag(SPV_ERROR_INVALID_DATA)
                 << ext_inst_name() << ": "
                 << "expected operand Eta to be a 16 or 32-bit float scalar";
        }
        break;
      }

      case GLSLstd450InterpolateAtCentroid:
      case GLSLstd450InterpolateAtSample:
      case GLSLstd450InterpolateAtOffset: {
        if (!_.HasCapability(SpvCapabilityInterpolationFunction)) {
          return _.diag(SPV_ERROR_INVALID_CAPABILITY)
                 << ext_inst_name()
                 << " requires capability InterpolationFunction";
        }

        if (!_.IsFloatScalarOrVectorType(result_type) ||
            _.GetBitWidth(result_type) != 32) {
          return _.diag(SPV_ERROR_INVALID_DATA)
                 << ext_inst_name() << ": "
                 << "expected Result Type to be a 32-bit float scalar "
                 << "or vector type";
        }

        const uint32_t interpolant_type = _.GetOperandTypeId(inst, 4);
        uint32_t interpolant_storage_class = 0;
        uint32_t interpolant_data_type = 0;
        if (!_.GetPointerTypeInfo(interpolant_type, &interpolant_data_type,
                                  &interpolant_storage_class)) {
          return _.diag(SPV_ERROR_INVALID_DATA)
                 << ext_inst_name() << ": "
                 << "expected Interpolant to be a pointer";
        }

        if (result_type != interpolant_data_type) {
          return _.diag(SPV_ERROR_INVALID_DATA)
                 << ext_inst_name() << ": "
                 << "expected Interpolant data type to be equal to Result Type";
        }

        if (interpolant_storage_class != SpvStorageClassInput) {
          return _.diag(SPV_ERROR_INVALID_DATA)
                 << ext_inst_name() << ": "
                 << "expected Interpolant storage class to be Input";
        }

        if (ext_inst_key == GLSLstd450InterpolateAtSample) {
          const uint32_t sample_type = _.GetOperandTypeId(inst, 5);
          if (!_.IsIntScalarType(sample_type) ||
              _.GetBitWidth(sample_type) != 32) {
            return _.diag(SPV_ERROR_INVALID_DATA)
                   << ext_inst_name() << ": "
                   << "expected Sample to be 32-bit integer";
          }
        }

        if (ext_inst_key == GLSLstd450InterpolateAtOffset) {
          const uint32_t offset_type = _.GetOperandTypeId(inst, 5);
          if (!_.IsFloatVectorType(offset_type) ||
              _.GetDimension(offset_type) != 2 ||
              _.GetBitWidth(offset_type) != 32) {
            return _.diag(SPV_ERROR_INVALID_DATA)
                   << ext_inst_name() << ": "
                   << "expected Offset to be a vector of 2 32-bit floats";
          }
        }

        _.current_function().RegisterExecutionModelLimitation(
            SpvExecutionModelFragment,
            ext_inst_name() +
                std::string(" requires Fragment execution model"));
        break;
      }

      case GLSLstd450IMix: {
        return _.diag(SPV_ERROR_INVALID_DATA)
               << "Extended instruction GLSLstd450IMix is not supported";
      }

      case GLSLstd450Bad: {
        return _.diag(SPV_ERROR_INVALID_DATA)
               << "Encountered extended instruction GLSLstd450Bad";
      }

      case GLSLstd450Count: {
        assert(0);
        break;
      }
    }
  } else if (ext_inst_type == SPV_EXT_INST_TYPE_OPENCL_STD) {
    const OpenCLLIB::Entrypoints ext_inst_key =
        OpenCLLIB::Entrypoints(ext_inst_index);
    switch (ext_inst_key) {
      case OpenCLLIB::Acos:
      case OpenCLLIB::Acosh:
      case OpenCLLIB::Acospi:
      case OpenCLLIB::Asin:
      case OpenCLLIB::Asinh:
      case OpenCLLIB::Asinpi:
      case OpenCLLIB::Atan:
      case OpenCLLIB::Atan2:
      case OpenCLLIB::Atanh:
      case OpenCLLIB::Atanpi:
      case OpenCLLIB::Atan2pi:
      case OpenCLLIB::Cbrt:
      case OpenCLLIB::Ceil:
      case OpenCLLIB::Copysign:
      case OpenCLLIB::Cos:
      case OpenCLLIB::Cosh:
      case OpenCLLIB::Cospi:
      case OpenCLLIB::Erfc:
      case OpenCLLIB::Erf:
      case OpenCLLIB::Exp:
      case OpenCLLIB::Exp2:
      case OpenCLLIB::Exp10:
      case OpenCLLIB::Expm1:
      case OpenCLLIB::Fabs:
      case OpenCLLIB::Fdim:
      case OpenCLLIB::Floor:
      case OpenCLLIB::Fma:
      case OpenCLLIB::Fmax:
      case OpenCLLIB::Fmin:
      case OpenCLLIB::Fmod:
      case OpenCLLIB::Hypot:
      case OpenCLLIB::Lgamma:
      case OpenCLLIB::Log:
      case OpenCLLIB::Log2:
      case OpenCLLIB::Log10:
      case OpenCLLIB::Log1p:
      case OpenCLLIB::Logb:
      case OpenCLLIB::Mad:
      case OpenCLLIB::Maxmag:
      case OpenCLLIB::Minmag:
      case OpenCLLIB::Nextafter:
      case OpenCLLIB::Pow:
      case OpenCLLIB::Powr:
      case OpenCLLIB::Remainder:
      case OpenCLLIB::Rint:
      case OpenCLLIB::Round:
      case OpenCLLIB::Rsqrt:
      case OpenCLLIB::Sin:
      case OpenCLLIB::Sinh:
      case OpenCLLIB::Sinpi:
      case OpenCLLIB::Sqrt:
      case OpenCLLIB::Tan:
      case OpenCLLIB::Tanh:
      case OpenCLLIB::Tanpi:
      case OpenCLLIB::Tgamma:
      case OpenCLLIB::Trunc:
      case OpenCLLIB::Half_cos:
      case OpenCLLIB::Half_divide:
      case OpenCLLIB::Half_exp:
      case OpenCLLIB::Half_exp2:
      case OpenCLLIB::Half_exp10:
      case OpenCLLIB::Half_log:
      case OpenCLLIB::Half_log2:
      case OpenCLLIB::Half_log10:
      case OpenCLLIB::Half_powr:
      case OpenCLLIB::Half_recip:
      case OpenCLLIB::Half_rsqrt:
      case OpenCLLIB::Half_sin:
      case OpenCLLIB::Half_sqrt:
      case OpenCLLIB::Half_tan:
      case OpenCLLIB::Native_cos:
      case OpenCLLIB::Native_divide:
      case OpenCLLIB::Native_exp:
      case OpenCLLIB::Native_exp2:
      case OpenCLLIB::Native_exp10:
      case OpenCLLIB::Native_log:
      case OpenCLLIB::Native_log2:
      case OpenCLLIB::Native_log10:
      case OpenCLLIB::Native_powr:
      case OpenCLLIB::Native_recip:
      case OpenCLLIB::Native_rsqrt:
      case OpenCLLIB::Native_sin:
      case OpenCLLIB::Native_sqrt:
      case OpenCLLIB::Native_tan:
      case OpenCLLIB::FClamp:
      case OpenCLLIB::Degrees:
      case OpenCLLIB::FMax_common:
      case OpenCLLIB::FMin_common:
      case OpenCLLIB::Mix:
      case OpenCLLIB::Radians:
      case OpenCLLIB::Step:
      case OpenCLLIB::Smoothstep:
      case OpenCLLIB::Sign: {
        if (!_.IsFloatScalarOrVectorType(result_type)) {
          return _.diag(SPV_ERROR_INVALID_DATA)
                 << ext_inst_name() << ": "
                 << "expected Result Type to be a float scalar or vector type";
        }

        const uint32_t num_components = _.GetDimension(result_type);
        if (num_components > 4 && num_components != 8 && num_components != 16) {
          return _.diag(SPV_ERROR_INVALID_DATA)
                 << ext_inst_name() << ": "
                 << "expected Result Type to be a scalar or a vector with 2, "
                    "3, 4, 8 or 16 components";
        }

        for (uint32_t operand_index = 4; operand_index < num_operands;
             ++operand_index) {
          const uint32_t operand_type = _.GetOperandTypeId(inst, operand_index);
          if (result_type != operand_type) {
            return _.diag(SPV_ERROR_INVALID_DATA)
                   << ext_inst_name() << ": "
                   << "expected types of all operands to be equal to Result "
                      "Type";
          }
        }
        break;
      }

      case OpenCLLIB::Fract:
      case OpenCLLIB::Modf:
      case OpenCLLIB::Sincos:
      case OpenCLLIB::Remquo: {
        if (!_.IsFloatScalarOrVectorType(result_type)) {
          return _.diag(SPV_ERROR_INVALID_DATA)
                 << ext_inst_name() << ": "
                 << "expected Result Type to be a float scalar or vector type";
        }

        const uint32_t num_components = _.GetDimension(result_type);
        if (num_components > 4 && num_components != 8 && num_components != 16) {
          return _.diag(SPV_ERROR_INVALID_DATA)
                 << ext_inst_name() << ": "
                 << "expected Result Type to be a scalar or a vector with 2, "
                    "3, 4, 8 or 16 components";
        }

        uint32_t operand_index = 4;
        const uint32_t x_type = _.GetOperandTypeId(inst, operand_index++);
        if (result_type != x_type) {
          return _.diag(SPV_ERROR_INVALID_DATA)
                 << ext_inst_name() << ": "
                 << "expected type of operand X to be equal to Result Type";
        }

        if (ext_inst_key == OpenCLLIB::Remquo) {
          const uint32_t y_type = _.GetOperandTypeId(inst, operand_index++);
          if (result_type != y_type) {
            return _.diag(SPV_ERROR_INVALID_DATA)
                   << ext_inst_name() << ": "
                   << "expected type of operand Y to be equal to Result Type";
          }
        }

        const uint32_t p_type = _.GetOperandTypeId(inst, operand_index++);
        uint32_t p_storage_class = 0;
        uint32_t p_data_type = 0;
        if (!_.GetPointerTypeInfo(p_type, &p_data_type, &p_storage_class)) {
          return _.diag(SPV_ERROR_INVALID_DATA)
                 << ext_inst_name() << ": "
                 << "expected the last operand to be a pointer";
        }

        if (p_storage_class != SpvStorageClassGeneric &&
            p_storage_class != SpvStorageClassCrossWorkgroup &&
            p_storage_class != SpvStorageClassWorkgroup &&
            p_storage_class != SpvStorageClassFunction) {
          return _.diag(SPV_ERROR_INVALID_DATA)
                 << ext_inst_name() << ": "
                 << "expected storage class of the pointer to be Generic, "
                    "CrossWorkgroup, Workgroup or Function";
        }

        if (result_type != p_data_type) {
          return _.diag(SPV_ERROR_INVALID_DATA)
                 << ext_inst_name() << ": "
                 << "expected data type of the pointer to be equal to Result "
                    "Type";
        }
        break;
      }

      case OpenCLLIB::Frexp:
      case OpenCLLIB::Lgamma_r: {
        if (!_.IsFloatScalarOrVectorType(result_type)) {
          return _.diag(SPV_ERROR_INVALID_DATA)
                 << ext_inst_name() << ": "
                 << "expected Result Type to be a float scalar or vector type";
        }

        const uint32_t num_components = _.GetDimension(result_type);
        if (num_components > 4 && num_components != 8 && num_components != 16) {
          return _.diag(SPV_ERROR_INVALID_DATA)
                 << ext_inst_name() << ": "
                 << "expected Result Type to be a scalar or a vector with 2, "
                    "3, 4, 8 or 16 components";
        }

        const uint32_t x_type = _.GetOperandTypeId(inst, 4);
        if (result_type != x_type) {
          return _.diag(SPV_ERROR_INVALID_DATA)
                 << ext_inst_name() << ": "
                 << "expected type of operand X to be equal to Result Type";
        }

        const uint32_t p_type = _.GetOperandTypeId(inst, 5);
        uint32_t p_storage_class = 0;
        uint32_t p_data_type = 0;
        if (!_.GetPointerTypeInfo(p_type, &p_data_type, &p_storage_class)) {
          return _.diag(SPV_ERROR_INVALID_DATA)
                 << ext_inst_name() << ": "
                 << "expected the last operand to be a pointer";
        }

        if (p_storage_class != SpvStorageClassGeneric &&
            p_storage_class != SpvStorageClassCrossWorkgroup &&
            p_storage_class != SpvStorageClassWorkgroup &&
            p_storage_class != SpvStorageClassFunction) {
          return _.diag(SPV_ERROR_INVALID_DATA)
                 << ext_inst_name() << ": "
                 << "expected storage class of the pointer to be Generic, "
                    "CrossWorkgroup, Workgroup or Function";
        }

        if (!_.IsIntScalarOrVectorType(p_data_type) ||
            _.GetBitWidth(p_data_type) != 32) {
          return _.diag(SPV_ERROR_INVALID_DATA)
                 << ext_inst_name() << ": "
                 << "expected data type of the pointer to be a 32-bit int "
                    "scalar or vector type";
        }

        if (_.GetDimension(p_data_type) != num_components) {
          return _.diag(SPV_ERROR_INVALID_DATA)
                 << ext_inst_name() << ": "
                 << "expected data type of the pointer to have the same number "
                    "of components as Result Type";
        }
        break;
      }

      case OpenCLLIB::Ilogb: {
        if (!_.IsIntScalarOrVectorType(result_type) ||
            _.GetBitWidth(result_type) != 32) {
          return _.diag(SPV_ERROR_INVALID_DATA)
                 << ext_inst_name() << ": "
                 << "expected Result Type to be a 32-bit int scalar or vector "
                    "type";
        }

        const uint32_t num_components = _.GetDimension(result_type);
        if (num_components > 4 && num_components != 8 && num_components != 16) {
          return _.diag(SPV_ERROR_INVALID_DATA)
                 << ext_inst_name() << ": "
                 << "expected Result Type to be a scalar or a vector with 2, "
                    "3, 4, 8 or 16 components";
        }

        const uint32_t x_type = _.GetOperandTypeId(inst, 4);
        if (!_.IsFloatScalarOrVectorType(x_type)) {
          return _.diag(SPV_ERROR_INVALID_DATA)
                 << ext_inst_name() << ": "
                 << "expected operand X to be a float scalar or vector";
        }

        if (_.GetDimension(x_type) != num_components) {
          return _.diag(SPV_ERROR_INVALID_DATA)
                 << ext_inst_name() << ": "
                 << "expected operand X to have the same number of components "
                    "as Result Type";
        }
        break;
      }

      case OpenCLLIB::Ldexp:
      case OpenCLLIB::Pown:
      case OpenCLLIB::Rootn: {
        if (!_.IsFloatScalarOrVectorType(result_type)) {
          return _.diag(SPV_ERROR_INVALID_DATA)
                 << ext_inst_name() << ": "
                 << "expected Result Type to be a float scalar or vector type";
        }

        const uint32_t num_components = _.GetDimension(result_type);
        if (num_components > 4 && num_components != 8 && num_components != 16) {
          return _.diag(SPV_ERROR_INVALID_DATA)
                 << ext_inst_name() << ": "
                 << "expected Result Type to be a scalar or a vector with 2, "
                    "3, 4, 8 or 16 components";
        }

        const uint32_t x_type = _.GetOperandTypeId(inst, 4);
        if (result_type != x_type) {
          return _.diag(SPV_ERROR_INVALID_DATA)
                 << ext_inst_name() << ": "
                 << "expected type of operand X to be equal to Result Type";
        }

        const uint32_t exp_type = _.GetOperandTypeId(inst, 5);
        if (!_.IsIntScalarOrVectorType(exp_type) ||
            _.GetBitWidth(exp_type) != 32) {
          return _.diag(SPV_ERROR_INVALID_DATA)
                 << ext_inst_name() << ": "
                 << "expected the exponent to be a 32-bit int scalar or vector";
        }

        if (_.GetDimension(exp_type) != num_components) {
          return _.diag(SPV_ERROR_INVALID_DATA)
                 << ext_inst_name() << ": "
                 << "expected the exponent to have the same number of "
                    "components as Result Type";
        }
        break;
      }

      case OpenCLLIB::Nan: {
        if (!_.IsFloatScalarOrVectorType(result_type)) {
          return _.diag(SPV_ERROR_INVALID_DATA)
                 << ext_inst_name() << ": "
                 << "expected Result Type to be a float scalar or vector type";
        }

        const uint32_t num_components = _.GetDimension(result_type);
        if (num_components > 4 && num_components != 8 && num_components != 16) {
          return _.diag(SPV_ERROR_INVALID_DATA)
                 << ext_inst_name() << ": "
                 << "expected Result Type to be a scalar or a vector with 2, "
                    "3, 4, 8 or 16 components";
        }

        const uint32_t nancode_type = _.GetOperandTypeId(inst, 4);
        if (!_.IsIntScalarOrVectorType(nancode_type)) {
          return _.diag(SPV_ERROR_INVALID_DATA)
                 << ext_inst_name() << ": "
                 << "expected Nancode to be an int scalar or vector type";
        }

        if (_.GetDimension(nancode_type) != num_components) {
          return _.diag(SPV_ERROR_INVALID_DATA)
                 << ext_inst_name() << ": "
                 << "expected Nancode to have the same number of components as "
                    "Result Type";
        }

        if (_.GetBitWidth(result_type) != _.GetBitWidth(nancode_type)) {
          return _.diag(SPV_ERROR_INVALID_DATA)
                 << ext_inst_name() << ": "
                 << "expected Nancode to have the same bit width as Result "
                    "Type";
        }
        break;
      }

      case OpenCLLIB::SAbs:
      case OpenCLLIB::SAbs_diff:
      case OpenCLLIB::SAdd_sat:
      case OpenCLLIB::UAdd_sat:
      case OpenCLLIB::SHadd:
      case OpenCLLIB::UHadd:
      case OpenCLLIB::SRhadd:
      case OpenCLLIB::URhadd:
      case OpenCLLIB::SClamp:
      case OpenCLLIB::UClamp:
      case OpenCLLIB::Clz:
      case OpenCLLIB::Ctz:
      case OpenCLLIB::SMad_hi:
      case OpenCLLIB::UMad_sat:
      case OpenCLLIB::SMad_sat:
      case OpenCLLIB::SMax:
      case OpenCLLIB::UMax:
      case OpenCLLIB::SMin:
      case OpenCLLIB::UMin:
      case OpenCLLIB::SMul_hi:
      case OpenCLLIB::Rotate:
      case OpenCLLIB::SSub_sat:
      case OpenCLLIB::USub_sat:
      case OpenCLLIB::Popcount:
      case OpenCLLIB::UAbs:
      case OpenCLLIB::UAbs_diff:
      case OpenCLLIB::UMul_hi:
      case OpenCLLIB::UMad_hi: {
        if (!_.IsIntScalarOrVectorType(result_type)) {
          return _.diag(SPV_ERROR_INVALID_DATA)
                 << ext_inst_name() << ": "
                 << "expected Result Type to be an int scalar or vector type";
        }

        const uint32_t num_components = _.GetDimension(result_type);
        if (num_components > 4 && num_components != 8 && num_components != 16) {
          return _.diag(SPV_ERROR_INVALID_DATA)
                 << ext_inst_name() << ": "
                 << "expected Result Type to be a scalar or a vector with 2, "
                    "3, 4, 8 or 16 components";
        }

        for (uint32_t operand_index = 4; operand_index < num_operands;
             ++operand_index) {
          const uint32_t operand_type = _.GetOperandTypeId(inst, operand_index);
          if (result_type != operand_type) {
            return _.diag(SPV_ERROR_INVALID_DATA)
                   << ext_inst_name() << ": "
                   << "expected types of all operands to be equal to Result "
                      "Type";
          }
        }
        break;
      }

      case OpenCLLIB::U_Upsample:
      case OpenCLLIB::S_Upsample: {
        if (!_.IsIntScalarOrVectorType(result_type)) {
          return _.diag(SPV_ERROR_INVALID_DATA)
                 << ext_inst_name() << ": "
                 << "expected Result Type to be an int scalar or vector "
                    "type";
        }

        const uint32_t result_num_components = _.GetDimension(result_type);
        if (result_num_components > 4 && result_num_components != 8 &&
            result_num_components != 16) {
          return _.diag(SPV_ERROR_INVALID_DATA)
                 << ext_inst_name() << ": "
                 << "expected Result Type to be a scalar or a vector with 2, "
                    "3, 4, 8 or 16 components";
        }

        const uint32_t result_bit_width = _.GetBitWidth(result_type);
        if (result_bit_width != 16 && result_bit_width != 32 &&
            result_bit_width != 64) {
          return _.diag(SPV_ERROR_INVALID_DATA)
                 << ext_inst_name() << ": "
                 << "expected bit width of Result Type components to be 16, 32 "
                    "or 64";
        }

        const uint32_t hi_type = _.GetOperandTypeId(inst, 4);
        const uint32_t lo_type = _.GetOperandTypeId(inst, 5);

        if (hi_type != lo_type) {
          return _.diag(SPV_ERROR_INVALID_DATA)
                 << ext_inst_name() << ": "
                 << "expected Hi and Lo operands to have the same type";
        }

        if (result_num_components != _.GetDimension(hi_type)) {
          return _.diag(SPV_ERROR_INVALID_DATA)
                 << ext_inst_name() << ": "
                 << "expected Hi and Lo operands to have the same number of "
                    "components as Result Type";
        }

        if (result_bit_width != 2 * _.GetBitWidth(hi_type)) {
          return _.diag(SPV_ERROR_INVALID_DATA)
                 << ext_inst_name() << ": "
                 << "expected bit width of components of Hi and Lo operands to "
                    "be half of the bit width of components of Result Type";
        }
        break;
      }

      case OpenCLLIB::SMad24:
      case OpenCLLIB::UMad24:
      case OpenCLLIB::SMul24:
      case OpenCLLIB::UMul24: {
        if (!_.IsIntScalarOrVectorType(result_type) ||
            _.GetBitWidth(result_type) != 32) {
          return _.diag(SPV_ERROR_INVALID_DATA)
                 << ext_inst_name() << ": "
                 << "expected Result Type to be a 32-bit int scalar or vector "
                    "type";
        }

        const uint32_t num_components = _.GetDimension(result_type);
        if (num_components > 4 && num_components != 8 && num_components != 16) {
          return _.diag(SPV_ERROR_INVALID_DATA)
                 << ext_inst_name() << ": "
                 << "expected Result Type to be a scalar or a vector with 2, "
                    "3, 4, 8 or 16 components";
        }

        for (uint32_t operand_index = 4; operand_index < num_operands;
             ++operand_index) {
          const uint32_t operand_type = _.GetOperandTypeId(inst, operand_index);
          if (result_type != operand_type) {
            return _.diag(SPV_ERROR_INVALID_DATA)
                   << ext_inst_name() << ": "
                   << "expected types of all operands to be equal to Result "
                      "Type";
          }
        }
        break;
      }

      case OpenCLLIB::Cross: {
        if (!_.IsFloatVectorType(result_type)) {
          return _.diag(SPV_ERROR_INVALID_DATA)
                 << ext_inst_name() << ": "
                 << "expected Result Type to be a float vector type";
        }

        const uint32_t num_components = _.GetDimension(result_type);
        if (num_components != 3 && num_components != 4) {
          return _.diag(SPV_ERROR_INVALID_DATA)
                 << ext_inst_name() << ": "
                 << "expected Result Type to have 3 or 4 components";
        }

        const uint32_t x_type = _.GetOperandTypeId(inst, 4);
        const uint32_t y_type = _.GetOperandTypeId(inst, 5);

        if (x_type != result_type) {
          return _.diag(SPV_ERROR_INVALID_DATA)
                 << ext_inst_name() << ": "
                 << "expected operand X type to be equal to Result Type";
        }

        if (y_type != result_type) {
          return _.diag(SPV_ERROR_INVALID_DATA)
                 << ext_inst_name() << ": "
                 << "expected operand Y type to be equal to Result Type";
        }
        break;
      }

      case OpenCLLIB::Distance:
      case OpenCLLIB::Fast_distance: {
        if (!_.IsFloatScalarType(result_type)) {
          return _.diag(SPV_ERROR_INVALID_DATA)
                 << ext_inst_name() << ": "
                 << "expected Result Type to be a float scalar type";
        }

        const uint32_t p0_type = _.GetOperandTypeId(inst, 4);
        if (!_.IsFloatScalarOrVectorType(p0_type)) {
          return _.diag(SPV_ERROR_INVALID_DATA)
                 << ext_inst_name() << ": "
                 << "expected operand P0 to be of float scalar or vector type";
        }

        const uint32_t num_components = _.GetDimension(p0_type);
        if (num_components > 4) {
          return _.diag(SPV_ERROR_INVALID_DATA)
                 << ext_inst_name() << ": "
                 << "expected operand P0 to have no more than 4 components";
        }

        if (result_type != _.GetComponentType(p0_type)) {
          return _.diag(SPV_ERROR_INVALID_DATA)
                 << ext_inst_name() << ": "
                 << "expected operand P0 component type to be equal to "
                 << "Result Type";
        }

        const uint32_t p1_type = _.GetOperandTypeId(inst, 5);
        if (p0_type != p1_type) {
          return _.diag(SPV_ERROR_INVALID_DATA)
                 << ext_inst_name() << ": "
                 << "expected operands P0 and P1 to be of the same type";
        }
        break;
      }

      case OpenCLLIB::Length:
      case OpenCLLIB::Fast_length: {
        if (!_.IsFloatScalarType(result_type)) {
          return _.diag(SPV_ERROR_INVALID_DATA)
                 << ext_inst_name() << ": "
                 << "expected Result Type to be a float scalar type";
        }

        const uint32_t p_type = _.GetOperandTypeId(inst, 4);
        if (!_.IsFloatScalarOrVectorType(p_type)) {
          return _.diag(SPV_ERROR_INVALID_DATA)
                 << ext_inst_name() << ": "
                 << "expected operand P to be a float scalar or vector";
        }

        const uint32_t num_components = _.GetDimension(p_type);
        if (num_components > 4) {
          return _.diag(SPV_ERROR_INVALID_DATA)
                 << ext_inst_name() << ": "
                 << "expected operand P to have no more than 4 components";
        }

        if (result_type != _.GetComponentType(p_type)) {
          return _.diag(SPV_ERROR_INVALID_DATA)
                 << ext_inst_name() << ": "
                 << "expected operand P component type to be equal to Result "
                    "Type";
        }
        break;
      }

      case OpenCLLIB::Normalize:
      case OpenCLLIB::Fast_normalize: {
        if (!_.IsFloatScalarOrVectorType(result_type)) {
          return _.diag(SPV_ERROR_INVALID_DATA)
                 << ext_inst_name() << ": "
                 << "expected Result Type to be a float scalar or vector type";
        }

        const uint32_t num_components = _.GetDimension(result_type);
        if (num_components > 4) {
          return _.diag(SPV_ERROR_INVALID_DATA)
                 << ext_inst_name() << ": "
                 << "expected Result Type to have no more than 4 components";
        }

        const uint32_t p_type = _.GetOperandTypeId(inst, 4);
        if (p_type != result_type) {
          return _.diag(SPV_ERROR_INVALID_DATA)
                 << ext_inst_name() << ": "
                 << "expected operand P type to be equal to Result Type";
        }
        break;
      }

      case OpenCLLIB::Bitselect: {
        if (!_.IsFloatScalarOrVectorType(result_type) &&
            !_.IsIntScalarOrVectorType(result_type)) {
          return _.diag(SPV_ERROR_INVALID_DATA)
                 << ext_inst_name() << ": "
                 << "expected Result Type to be an int or float scalar or "
                    "vector type";
        }

        const uint32_t num_components = _.GetDimension(result_type);
        if (num_components > 4 && num_components != 8 && num_components != 16) {
          return _.diag(SPV_ERROR_INVALID_DATA)
                 << ext_inst_name() << ": "
                 << "expected Result Type to be a scalar or a vector with 2, "
                    "3, 4, 8 or 16 components";
        }

        for (uint32_t operand_index = 4; operand_index < num_operands;
             ++operand_index) {
          const uint32_t operand_type = _.GetOperandTypeId(inst, operand_index);
          if (result_type != operand_type) {
            return _.diag(SPV_ERROR_INVALID_DATA)
                   << ext_inst_name() << ": "
                   << "expected types of all operands to be equal to Result "
                      "Type";
          }
        }
        break;
      }

      case OpenCLLIB::Select: {
        if (!_.IsFloatScalarOrVectorType(result_type) &&
            !_.IsIntScalarOrVectorType(result_type)) {
          return _.diag(SPV_ERROR_INVALID_DATA)
                 << ext_inst_name() << ": "
                 << "expected Result Type to be an int or float scalar or "
                    "vector type";
        }

        const uint32_t num_components = _.GetDimension(result_type);
        if (num_components > 4 && num_components != 8 && num_components != 16) {
          return _.diag(SPV_ERROR_INVALID_DATA)
                 << ext_inst_name() << ": "
                 << "expected Result Type to be a scalar or a vector with 2, "
                    "3, 4, 8 or 16 components";
        }

        const uint32_t a_type = _.GetOperandTypeId(inst, 4);
        const uint32_t b_type = _.GetOperandTypeId(inst, 5);
        const uint32_t c_type = _.GetOperandTypeId(inst, 6);

        if (result_type != a_type) {
          return _.diag(SPV_ERROR_INVALID_DATA)
                 << ext_inst_name() << ": "
                 << "expected operand A type to be equal to Result Type";
        }

        if (result_type != b_type) {
          return _.diag(SPV_ERROR_INVALID_DATA)
                 << ext_inst_name() << ": "
                 << "expected operand B type to be equal to Result Type";
        }

        if (!_.IsIntScalarOrVectorType(c_type)) {
          return _.diag(SPV_ERROR_INVALID_DATA)
                 << ext_inst_name() << ": "
                 << "expected operand C to be an int scalar or vector";
        }

        if (num_components != _.GetDimension(c_type)) {
          return _.diag(SPV_ERROR_INVALID_DATA)
                 << ext_inst_name() << ": "
                 << "expected operand C to have the same number of components "
                    "as Result Type";
        }

        if (_.GetBitWidth(result_type) != _.GetBitWidth(c_type)) {
          return _.diag(SPV_ERROR_INVALID_DATA)
                 << ext_inst_name() << ": "
                 << "expected operand C to have the same bit width as Result "
                    "Type";
        }
        break;
      }

      case OpenCLLIB::Vloadn: {
        if (!_.IsFloatVectorType(result_type) &&
            !_.IsIntVectorType(result_type)) {
          return _.diag(SPV_ERROR_INVALID_DATA)
                 << ext_inst_name() << ": "
                 << "expected Result Type to be an int or float vector type";
        }

        const uint32_t num_components = _.GetDimension(result_type);
        if (num_components > 4 && num_components != 8 && num_components != 16) {
          return _.diag(SPV_ERROR_INVALID_DATA)
                 << ext_inst_name() << ": "
                 << "expected Result Type to have 2, 3, 4, 8 or 16 components";
        }

        const uint32_t offset_type = _.GetOperandTypeId(inst, 4);
        const uint32_t p_type = _.GetOperandTypeId(inst, 5);

        const uint32_t size_t_bit_width = GetSizeTBitWidth(_);
        if (!size_t_bit_width) {
          return _.diag(SPV_ERROR_INVALID_DATA)
                 << ext_inst_name()
                 << " can only be used with physical addressing models";
        }

        if (!_.IsIntScalarType(offset_type) ||
            _.GetBitWidth(offset_type) != size_t_bit_width) {
          return _.diag(SPV_ERROR_INVALID_DATA)
                 << ext_inst_name() << ": "
                 << "expected operand Offset to be of type size_t ("
                 << size_t_bit_width
                 << "-bit integer for the addressing model used in the module)";
        }

        uint32_t p_storage_class = 0;
        uint32_t p_data_type = 0;
        if (!_.GetPointerTypeInfo(p_type, &p_data_type, &p_storage_class)) {
          return _.diag(SPV_ERROR_INVALID_DATA)
                 << ext_inst_name() << ": "
                 << "expected operand P to be a pointer";
        }

        if (p_storage_class != SpvStorageClassUniformConstant &&
            p_storage_class != SpvStorageClassGeneric) {
          return _.diag(SPV_ERROR_INVALID_DATA)
                 << ext_inst_name() << ": "
                 << "expected operand P storage class to be UniformConstant or "
                    "Generic";
        }

        if (_.GetComponentType(result_type) != p_data_type) {
          return _.diag(SPV_ERROR_INVALID_DATA)
                 << ext_inst_name() << ": "
                 << "expected operand P data type to be equal to component "
                    "type of Result Type";
        }

        const uint32_t n_value = inst->words[7];
        if (num_components != n_value) {
          return _.diag(SPV_ERROR_INVALID_DATA)
                 << ext_inst_name() << ": "
                 << "expected literal N to be equal to the number of "
                    "components of Result Type";
        }
        break;
      }

      case OpenCLLIB::Vstoren: {
        if (_.GetIdOpcode(result_type) != SpvOpTypeVoid) {
          return _.diag(SPV_ERROR_INVALID_DATA)
                 << ext_inst_name() << ": expected Result Type to be void";
        }

        const uint32_t data_type = _.GetOperandTypeId(inst, 4);
        const uint32_t offset_type = _.GetOperandTypeId(inst, 5);
        const uint32_t p_type = _.GetOperandTypeId(inst, 6);

        if (!_.IsFloatVectorType(data_type) && !_.IsIntVectorType(data_type)) {
          return _.diag(SPV_ERROR_INVALID_DATA)
                 << ext_inst_name() << ": "
                 << "expected Data to be an int or float vector";
        }

        const uint32_t num_components = _.GetDimension(data_type);
        if (num_components > 4 && num_components != 8 && num_components != 16) {
          return _.diag(SPV_ERROR_INVALID_DATA)
                 << ext_inst_name() << ": "
                 << "expected Data to have 2, 3, 4, 8 or 16 components";
        }

        const uint32_t size_t_bit_width = GetSizeTBitWidth(_);
        if (!size_t_bit_width) {
          return _.diag(SPV_ERROR_INVALID_DATA)
                 << ext_inst_name()
                 << " can only be used with physical addressing models";
        }

        if (!_.IsIntScalarType(offset_type) ||
            _.GetBitWidth(offset_type) != size_t_bit_width) {
          return _.diag(SPV_ERROR_INVALID_DATA)
                 << ext_inst_name() << ": "
                 << "expected operand Offset to be of type size_t ("
                 << size_t_bit_width
                 << "-bit integer for the addressing model used in the module)";
        }

        uint32_t p_storage_class = 0;
        uint32_t p_data_type = 0;
        if (!_.GetPointerTypeInfo(p_type, &p_data_type, &p_storage_class)) {
          return _.diag(SPV_ERROR_INVALID_DATA)
                 << ext_inst_name() << ": "
                 << "expected operand P to be a pointer";
        }

        if (p_storage_class != SpvStorageClassGeneric) {
          return _.diag(SPV_ERROR_INVALID_DATA)
                 << ext_inst_name() << ": "
                 << "expected operand P storage class to be Generic";
        }

        if (_.GetComponentType(data_type) != p_data_type) {
          return _.diag(SPV_ERROR_INVALID_DATA)
                 << ext_inst_name() << ": "
                 << "expected operand P data type to be equal to the type of "
                    "operand Data components";
        }
        break;
      }

      case OpenCLLIB::Vload_half: {
        if (!_.IsFloatScalarType(result_type)) {
          return _.diag(SPV_ERROR_INVALID_DATA)
                 << ext_inst_name() << ": "
                 << "expected Result Type to be a float scalar type";
        }

        const uint32_t offset_type = _.GetOperandTypeId(inst, 4);
        const uint32_t p_type = _.GetOperandTypeId(inst, 5);

        const uint32_t size_t_bit_width = GetSizeTBitWidth(_);
        if (!size_t_bit_width) {
          return _.diag(SPV_ERROR_INVALID_DATA)
                 << ext_inst_name()
                 << " can only be used with physical addressing models";
        }

        if (!_.IsIntScalarType(offset_type) ||
            _.GetBitWidth(offset_type) != size_t_bit_width) {
          return _.diag(SPV_ERROR_INVALID_DATA)
                 << ext_inst_name() << ": "
                 << "expected operand Offset to be of type size_t ("
                 << size_t_bit_width
                 << "-bit integer for the addressing model used in the module)";
        }

        uint32_t p_storage_class = 0;
        uint32_t p_data_type = 0;
        if (!_.GetPointerTypeInfo(p_type, &p_data_type, &p_storage_class)) {
          return _.diag(SPV_ERROR_INVALID_DATA)
                 << ext_inst_name() << ": "
                 << "expected operand P to be a pointer";
        }

        if (p_storage_class != SpvStorageClassUniformConstant &&
            p_storage_class != SpvStorageClassGeneric &&
            p_storage_class != SpvStorageClassCrossWorkgroup &&
            p_storage_class != SpvStorageClassWorkgroup &&
            p_storage_class != SpvStorageClassFunction) {
          return _.diag(SPV_ERROR_INVALID_DATA)
                 << ext_inst_name() << ": "
                 << "expected operand P storage class to be UniformConstant, "
                    "Generic, CrossWorkgroup, Workgroup or Function";
        }

        if (!_.IsFloatScalarType(p_data_type) ||
            _.GetBitWidth(p_data_type) != 16) {
          return _.diag(SPV_ERROR_INVALID_DATA)
                 << ext_inst_name() << ": "
                 << "expected operand P data type to be 16-bit float scalar";
        }
        break;
      }

      case OpenCLLIB::Vload_halfn:
      case OpenCLLIB::Vloada_halfn: {
        if (!_.IsFloatVectorType(result_type)) {
          return _.diag(SPV_ERROR_INVALID_DATA)
                 << ext_inst_name() << ": "
                 << "expected Result Type to be a float vector type";
        }

        const uint32_t num_components = _.GetDimension(result_type);
        if (num_components > 4 && num_components != 8 && num_components != 16) {
          return _.diag(SPV_ERROR_INVALID_DATA)
                 << ext_inst_name() << ": "
                 << "expected Result Type to have 2, 3, 4, 8 or 16 components";
        }

        const uint32_t offset_type = _.GetOperandTypeId(inst, 4);
        const uint32_t p_type = _.GetOperandTypeId(inst, 5);

        const uint32_t size_t_bit_width = GetSizeTBitWidth(_);
        if (!size_t_bit_width) {
          return _.diag(SPV_ERROR_INVALID_DATA)
                 << ext_inst_name()
                 << " can only be used with physical addressing models";
        }

        if (!_.IsIntScalarType(offset_type) ||
            _.GetBitWidth(offset_type) != size_t_bit_width) {
          return _.diag(SPV_ERROR_INVALID_DATA)
                 << ext_inst_name() << ": "
                 << "expected operand Offset to be of type size_t ("
                 << size_t_bit_width
                 << "-bit integer for the addressing model used in the module)";
        }

        uint32_t p_storage_class = 0;
        uint32_t p_data_type = 0;
        if (!_.GetPointerTypeInfo(p_type, &p_data_type, &p_storage_class)) {
          return _.diag(SPV_ERROR_INVALID_DATA)
                 << ext_inst_name() << ": "
                 << "expected operand P to be a pointer";
        }

        if (p_storage_class != SpvStorageClassUniformConstant &&
            p_storage_class != SpvStorageClassGeneric &&
            p_storage_class != SpvStorageClassCrossWorkgroup &&
            p_storage_class != SpvStorageClassWorkgroup &&
            p_storage_class != SpvStorageClassFunction) {
          return _.diag(SPV_ERROR_INVALID_DATA)
                 << ext_inst_name() << ": "
                 << "expected operand P storage class to be UniformConstant, "
                    "Generic, CrossWorkgroup, Workgroup or Function";
        }

        if (!_.IsFloatScalarType(p_data_type) ||
            _.GetBitWidth(p_data_type) != 16) {
          return _.diag(SPV_ERROR_INVALID_DATA)
                 << ext_inst_name() << ": "
                 << "expected operand P data type to be 16-bit float scalar";
        }

        const uint32_t n_value = inst->words[7];
        if (num_components != n_value) {
          return _.diag(SPV_ERROR_INVALID_DATA)
                 << ext_inst_name() << ": "
                 << "expected literal N to be equal to the number of "
                    "components of Result Type";
        }
        break;
      }

      case OpenCLLIB::Vstore_half:
      case OpenCLLIB::Vstore_half_r:
      case OpenCLLIB::Vstore_halfn:
      case OpenCLLIB::Vstore_halfn_r:
      case OpenCLLIB::Vstorea_halfn:
      case OpenCLLIB::Vstorea_halfn_r: {
        if (_.GetIdOpcode(result_type) != SpvOpTypeVoid) {
          return _.diag(SPV_ERROR_INVALID_DATA)
                 << ext_inst_name() << ": expected Result Type to be void";
        }

        const uint32_t data_type = _.GetOperandTypeId(inst, 4);
        const uint32_t offset_type = _.GetOperandTypeId(inst, 5);
        const uint32_t p_type = _.GetOperandTypeId(inst, 6);
        const uint32_t data_type_bit_width = _.GetBitWidth(data_type);

        if (ext_inst_key == OpenCLLIB::Vstore_half ||
            ext_inst_key == OpenCLLIB::Vstore_half_r) {
          if (!_.IsFloatScalarType(data_type) ||
              (data_type_bit_width != 32 && data_type_bit_width != 64)) {
            return _.diag(SPV_ERROR_INVALID_DATA)
                   << ext_inst_name() << ": "
                   << "expected Data to be a 32 or 64-bit float scalar";
          }
        } else {
          if (!_.IsFloatVectorType(data_type) ||
              (data_type_bit_width != 32 && data_type_bit_width != 64)) {
            return _.diag(SPV_ERROR_INVALID_DATA)
                   << ext_inst_name() << ": "
                   << "expected Data to be a 32 or 64-bit float vector";
          }

          const uint32_t num_components = _.GetDimension(data_type);
          if (num_components > 4 && num_components != 8 &&
              num_components != 16) {
            return _.diag(SPV_ERROR_INVALID_DATA)
                   << ext_inst_name() << ": "
                   << "expected Data to have 2, 3, 4, 8 or 16 components";
          }
        }

        const uint32_t size_t_bit_width = GetSizeTBitWidth(_);
        if (!size_t_bit_width) {
          return _.diag(SPV_ERROR_INVALID_DATA)
                 << ext_inst_name()
                 << " can only be used with physical addressing models";
        }

        if (!_.IsIntScalarType(offset_type) ||
            _.GetBitWidth(offset_type) != size_t_bit_width) {
          return _.diag(SPV_ERROR_INVALID_DATA)
                 << ext_inst_name() << ": "
                 << "expected operand Offset to be of type size_t ("
                 << size_t_bit_width
                 << "-bit integer for the addressing model used in the module)";
        }

        uint32_t p_storage_class = 0;
        uint32_t p_data_type = 0;
        if (!_.GetPointerTypeInfo(p_type, &p_data_type, &p_storage_class)) {
          return _.diag(SPV_ERROR_INVALID_DATA)
                 << ext_inst_name() << ": "
                 << "expected operand P to be a pointer";
        }

        if (p_storage_class != SpvStorageClassGeneric &&
            p_storage_class != SpvStorageClassCrossWorkgroup &&
            p_storage_class != SpvStorageClassWorkgroup &&
            p_storage_class != SpvStorageClassFunction) {
          return _.diag(SPV_ERROR_INVALID_DATA)
                 << ext_inst_name() << ": "
                 << "expected operand P storage class to be Generic, "
                    "CrossWorkgroup, Workgroup or Function";
        }

        if (!_.IsFloatScalarType(p_data_type) ||
            _.GetBitWidth(p_data_type) != 16) {
          return _.diag(SPV_ERROR_INVALID_DATA)
                 << ext_inst_name() << ": "
                 << "expected operand P data type to be 16-bit float scalar";
        }

        // Rounding mode enum is checked by assembler.
        break;
      }

      case OpenCLLIB::Shuffle:
      case OpenCLLIB::Shuffle2: {
        if (!_.IsFloatVectorType(result_type) &&
            !_.IsIntVectorType(result_type)) {
          return _.diag(SPV_ERROR_INVALID_DATA)
                 << ext_inst_name() << ": "
                 << "expected Result Type to be an int or float vector type";
        }

        const uint32_t result_num_components = _.GetDimension(result_type);
        if (result_num_components != 2 && result_num_components != 4 &&
            result_num_components != 8 && result_num_components != 16) {
          return _.diag(SPV_ERROR_INVALID_DATA)
                 << ext_inst_name() << ": "
                 << "expected Result Type to have 2, 4, 8 or 16 components";
        }

        uint32_t operand_index = 4;
        const uint32_t x_type = _.GetOperandTypeId(inst, operand_index++);

        if (ext_inst_key == OpenCLLIB::Shuffle2) {
          const uint32_t y_type = _.GetOperandTypeId(inst, operand_index++);
          if (x_type != y_type) {
            return _.diag(SPV_ERROR_INVALID_DATA)
                   << ext_inst_name() << ": "
                   << "expected operands X and Y to be of the same type";
          }
        }

        const uint32_t shuffle_mask_type =
            _.GetOperandTypeId(inst, operand_index++);

        if (!_.IsFloatVectorType(x_type) && !_.IsIntVectorType(x_type)) {
          return _.diag(SPV_ERROR_INVALID_DATA)
                 << ext_inst_name() << ": "
                 << "expected operand X to be an int or float vector";
        }

        const uint32_t x_num_components = _.GetDimension(x_type);
        if (x_num_components != 2 && x_num_components != 4 &&
            x_num_components != 8 && x_num_components != 16) {
          return _.diag(SPV_ERROR_INVALID_DATA)
                 << ext_inst_name() << ": "
                 << "expected operand X to have 2, 4, 8 or 16 components";
        }

        const uint32_t result_component_type = _.GetComponentType(result_type);

        if (result_component_type != _.GetComponentType(x_type)) {
          return _.diag(SPV_ERROR_INVALID_DATA)
                 << ext_inst_name() << ": "
                 << "expected operand X and Result Type to have equal "
                    "component types";
        }

        if (!_.IsIntVectorType(shuffle_mask_type)) {
          return _.diag(SPV_ERROR_INVALID_DATA)
                 << ext_inst_name() << ": "
                 << "expected operand Shuffle Mask to be an int vector";
        }

        if (result_num_components != _.GetDimension(shuffle_mask_type)) {
          return _.diag(SPV_ERROR_INVALID_DATA)
                 << ext_inst_name() << ": "
                 << "expected operand Shuffle Mask to have the same number of "
                    "components as Result Type";
        }

        if (_.GetBitWidth(result_component_type) !=
            _.GetBitWidth(shuffle_mask_type)) {
          return _.diag(SPV_ERROR_INVALID_DATA)
                 << ext_inst_name() << ": "
                 << "expected operand Shuffle Mask components to have the same "
                    "bit width as Result Type components";
        }
        break;
      }

      case OpenCLLIB::Printf: {
        if (!_.IsIntScalarType(result_type) ||
            _.GetBitWidth(result_type) != 32) {
          return _.diag(SPV_ERROR_INVALID_DATA)
                 << ext_inst_name() << ": "
                 << "expected Result Type to be a 32-bit int type";
        }

        const uint32_t format_type = _.GetOperandTypeId(inst, 4);
        uint32_t format_storage_class = 0;
        uint32_t format_data_type = 0;
        if (!_.GetPointerTypeInfo(format_type, &format_data_type,
                                  &format_storage_class)) {
          return _.diag(SPV_ERROR_INVALID_DATA)
                 << ext_inst_name() << ": "
                 << "expected operand Format to be a pointer";
        }

        if (format_storage_class != SpvStorageClassUniformConstant) {
          return _.diag(SPV_ERROR_INVALID_DATA)
                 << ext_inst_name() << ": "
                 << "expected Format storage class to be UniformConstant";
        }

        if (!_.IsIntScalarType(format_data_type) ||
            _.GetBitWidth(format_data_type) != 8) {
          return _.diag(SPV_ERROR_INVALID_DATA)
                 << ext_inst_name() << ": "
                 << "expected Format data type to be 8-bit int";
        }
        break;
      }

      case OpenCLLIB::Prefetch: {
        if (_.GetIdOpcode(result_type) != SpvOpTypeVoid) {
          return _.diag(SPV_ERROR_INVALID_DATA)
                 << ext_inst_name() << ": expected Result Type to be void";
        }

        const uint32_t p_type = _.GetOperandTypeId(inst, 4);
        const uint32_t num_elements_type = _.GetOperandTypeId(inst, 5);

        uint32_t p_storage_class = 0;
        uint32_t p_data_type = 0;
        if (!_.GetPointerTypeInfo(p_type, &p_data_type, &p_storage_class)) {
          return _.diag(SPV_ERROR_INVALID_DATA)
                 << ext_inst_name() << ": "
                 << "expected operand Ptr to be a pointer";
        }

        if (p_storage_class != SpvStorageClassCrossWorkgroup) {
          return _.diag(SPV_ERROR_INVALID_DATA)
                 << ext_inst_name() << ": "
                 << "expected operand Ptr storage class to be CrossWorkgroup";
        }

        if (!_.IsFloatScalarOrVectorType(p_data_type) &&
            !_.IsIntScalarOrVectorType(p_data_type)) {
          return _.diag(SPV_ERROR_INVALID_DATA)
                 << ext_inst_name() << ": "
                 << "expected Ptr data type to be int or float scalar or "
                    "vector";
        }

        const uint32_t num_components = _.GetDimension(p_data_type);
        if (num_components > 4 && num_components != 8 && num_components != 16) {
          return _.diag(SPV_ERROR_INVALID_DATA)
                 << ext_inst_name() << ": "
                 << "expected Result Type to be a scalar or a vector with 2, "
                    "3, 4, 8 or 16 components";
        }

        const uint32_t size_t_bit_width = GetSizeTBitWidth(_);
        if (!size_t_bit_width) {
          return _.diag(SPV_ERROR_INVALID_DATA)
                 << ext_inst_name()
                 << " can only be used with physical addressing models";
        }

        if (!_.IsIntScalarType(num_elements_type) ||
            _.GetBitWidth(num_elements_type) != size_t_bit_width) {
          return _.diag(SPV_ERROR_INVALID_DATA)
                 << ext_inst_name() << ": "
                 << "expected operand Num Elements to be of type size_t ("
                 << size_t_bit_width
                 << "-bit integer for the addressing model used in the module)";
        }
        break;
      }
    }
  }

  return SPV_SUCCESS;
}

}  // namespace libspirv


text:
from __future__ import unicode_literals

from sqlalchemy.orm import joinedload, subqueryload

from indico.core.db import db
from indico.core.db.sqlalchemy.principals import clone_principals
from indico.core.db.sqlalchemy.util.models import get_simple_column_attrs
from indico.modules.events.cloning import EventCloner
from indico.modules.events.sessions import Session
from indico.modules.events.sessions.models.blocks import SessionBlock
from indico.modules.events.sessions.models.persons import SessionBlockPersonLink
from indico.modules.events.sessions.models.principals import SessionPrincipal
from indico.util.i18n import _

class SessionCloner(EventCloner):
    name = 'sessions'
    friendly_name = _('Sessions')
    requires = {'event_persons'}
    is_internal = True

    # We do not override `is_available` as we have cloners depending
    # on this internal cloner even if it won't clone anything.

    def run(self, new_event, cloners, shared_data):
        self._person_map = shared_data['event_persons']['person_map']
        self._session_map = {}
        self._session_block_map = {}
        with db.session.no_autoflush:
            self._clone_sessions(new_event)
        self._synchronize_friendly_id(new_event)
        db.session.flush()
        return {'session_map': self._session_map, 'session_block_map': self._session_block_map}

    def _clone_sessions(self, new_event):
        attrs = get_simple_column_attrs(Session) | {'own_room', 'own_venue'}
        query = (Session.query.with_parent(self.old_event)
                 .options(joinedload('blocks'),
                          joinedload('own_venue'),
                          joinedload('own_room').lazyload('*'),
                          subqueryload('acl_entries')))
        for old_sess in query:
            sess = Session()
            sess.populate_from_attrs(old_sess, attrs)
            sess.blocks = list(self._clone_session_blocks(old_sess.blocks))
            sess.acl_entries = clone_principals(SessionPrincipal, old_sess.acl_entries)
            new_event.sessions.append(sess)
            self._session_map[old_sess] = sess

    def _clone_session_blocks(self, blocks):
        attrs = get_simple_column_attrs(SessionBlock) | {'own_room', 'own_venue'}
        for old_block in blocks:
            block = SessionBlock()
            block.populate_from_attrs(old_block, attrs)
            block.person_links = list(self._clone_person_links(old_block.person_links))
            self._session_block_map[old_block] = block
            yield block

    def _clone_person_links(self, person_links):
        attrs = get_simple_column_attrs(SessionBlockPersonLink)
        for old_link in person_links:
            link = SessionBlockPersonLink()
            link.populate_from_attrs(old_link, attrs)
            link.person = self._person_map[old_link.person]
            yield link

    def _synchronize_friendly_id(self, new_event):
        new_event._last_friendly_session_id = (
            db.session
            .query(db.func.max(Session.friendly_id))
            .filter(Session.event_id == new_event.id)
            .scalar() or 0
        )

redpajama_set_name: RedPajamaGithub


text:
require File.dirname(__FILE__) + '/spec_helper'

describe Translate::Storage do
  describe "write_to_file" do
    before(:each) do
      @storage = Translate::Storage.new(:en)
    end

    it "writes all I18n messages for a locale to YAML file" do
      I18n.backend.should_receive(:translations).and_return(translations)
      @storage.stub!(:file_path).and_return(file_path)
      file = mock(:file)
      file.should_receive(:write).with(translations)
      Translate::File.should_receive(:new).with(file_path).and_return(file)
      @storage.write_to_file
    end

    def file_path
      File.join(File.dirname(__FILE__), "files", "en.yml")
    end

    def translations
      {
        :en => {
          :article => {
            :title => "One Article"
          },
          :category => "Category"
        }
      }
    end
  end
end


text:
#!/usr/bin/env node

'use strict';

/* eslint-disable no-console */

/** @typedef {import('./constants').LanternSiteDefinition} LanternSiteDefinition */
/** @typedef {import('./constants').LanternEvaluation} LanternEvaluation */
/** @typedef {import('./constants').EstimateEvaluationSummary} EstimateEvaluationSummary */
/** @typedef {import('./constants').TargetMetrics} TargetMetrics */
/** @typedef {import('./constants').LanternMetrics} LanternMetrics */

const fs = require('fs');
const path = require('path');
const constants = require('./constants.js');
const chalk = require('chalk').default;

const GOOD_DIFF_AS_PERCENT_THRESHOLD = 0.2;
const OK_DIFF_AS_PERCENT_THRESHOLD = 0.5;

const INPUT_PATH = process.argv[2] || constants.SITE_INDEX_WITH_GOLDEN_WITH_COMPUTED_PATH;
const COMPUTATIONS_PATH = path.resolve(process.cwd(), INPUT_PATH);
const BASELINE_PATH = constants.MASTER_COMPUTED_PATH;

if (!fs.existsSync(COMPUTATIONS_PATH)) throw new Error('Usage $0 <computed summary file>');

/** @type {{sites: LanternSiteDefinition[]}} */
const siteIndexWithComputed = require(COMPUTATIONS_PATH);
const baselineLanternData = require(BASELINE_PATH);

const entries = constants.combineBaselineAndComputedDatasets(siteIndexWithComputed,
  baselineLanternData);

/** @param {LanternEvaluation} evaluation */
function isEvaluationGood(evaluation) {
  return evaluation.diffAsPercent < GOOD_DIFF_AS_PERCENT_THRESHOLD;
}
/** @param {LanternEvaluation} evaluation */
function isEvaluationOK(evaluation) {
  return (
    evaluation.diffAsPercent >= GOOD_DIFF_AS_PERCENT_THRESHOLD &&
    evaluation.diffAsPercent < OK_DIFF_AS_PERCENT_THRESHOLD
  );
}
/** @param {LanternEvaluation} evaluation */
function isEvaluationBad(evaluation) {
  return evaluation.diffAsPercent > OK_DIFF_AS_PERCENT_THRESHOLD;
}

/** @type {LanternEvaluation[]} */
const allEvaluations = [];
/** @type {LanternEvaluation[]} */
const baselineEvaluations = [];

/**
 * @param {number} actualValue
 * @param {number} baselineValue
 * @param {{isIncreaseGood?: boolean, format?: any, alwaysGray?: boolean}} [options]
 */
function toBaselineDiffString(actualValue, baselineValue, options) {
  options = {isIncreaseGood: false, format: toPercentString, ...options};
  const diffAsNumber = actualValue - baselineValue;
  const isGoingUp = diffAsNumber > 0;
  const isGood = options.isIncreaseGood === isGoingUp;

  let arrow = isGoingUp ? '↑' : '↓';
  let color = isGood ? chalk.green : chalk.red;
  if (options.alwaysGray) color = chalk.gray;

  if (Math.abs(diffAsNumber) < baselineValue * 0.01) {
    arrow = '↔';
    color = chalk.gray;
  } else if (Math.abs(diffAsNumber) > baselineValue * 0.1) {
    arrow = arrow + arrow;
  }

  const diffAsString = options.format(Math.abs(diffAsNumber));
  const text = `${arrow.padEnd(2)} ${diffAsString}`;
  return color(text);
}

/** @param {number} percentAsDecimal */
function toPercentString(percentAsDecimal) {
  return (percentAsDecimal * 100).toFixed(1) + '%';
}

/**
 * @param {keyof TargetMetrics} metric
 * @param {keyof LanternMetrics} lanternMetric
 */
function evaluateAndPrintAccuracy(metric, lanternMetric) {
  const actualAccuracy = constants.evaluateAccuracy(entries, metric, lanternMetric);
  const baselineAccuracy = constants.evaluateAccuracy(entries, metric, lanternMetric, 'baseline');
  const baselineOptions = {alwaysGray: !lanternMetric.includes('roughEstimate')};

  const strings = [
    lanternMetric.padEnd(25),
    `${toPercentString(actualAccuracy.p50)} ${toBaselineDiffString(
      actualAccuracy.p50,
      baselineAccuracy.p50,
      baselineOptions
    )}`.padEnd(30),
    `${toPercentString(actualAccuracy.p90)} ${toBaselineDiffString(
      actualAccuracy.p90,
      baselineAccuracy.p90,
      baselineOptions
    )}`.padEnd(30),
    `${toPercentString(actualAccuracy.p95)} ${toBaselineDiffString(
      actualAccuracy.p95,
      baselineAccuracy.p95,
      baselineOptions
    )}`.padEnd(30),
  ];

  allEvaluations.push(...actualAccuracy.evaluations);
  baselineEvaluations.push(...baselineAccuracy.evaluations);

  if (lanternMetric.includes('roughEstimate')) {
    console.log(...strings);
  } else {
    console.log(chalk.gray(...strings));
  }
}
/**
 * @param {keyof TargetMetrics} metric
 * @param {string[]} lanternMetrics
 */
function findAndPrintWorst10Sites(metric, lanternMetrics) {
  if (!process.env.PRINT_WORST) return;

  /** @type {Map<string, LanternEvaluation[]>} */
  const groupedByURL = new Map();
  for (const site of allEvaluations) {
    const group = groupedByURL.get(site.url) || [];
    group.push(site);
    groupedByURL.set(site.url, group);
  }

  /** @type {LanternEvaluation[]} */
  const worstEntries = [];
  for (const entries of groupedByURL.values()) {
    const matchingEntries = entries.filter(entry => lanternMetrics.includes(entry.lanternMetric));
    const minDiffAsPercent = Math.min(...matchingEntries.map(entry => entry.diffAsPercent));
    const minEntry = matchingEntries.find(entry => minDiffAsPercent === entry.diffAsPercent);
    if (!minEntry) continue;
    worstEntries.push(minEntry);
  }

  console.log(chalk.bold(`\n ------- Worst 10 ${metric} -------`));
  worstEntries
    .sort((a, b) => b.diffAsPercent - a.diffAsPercent)
    .slice(0, 10)
    .forEach(entry => {
      console.log(
        entry.actual < entry.expected
          ? chalk.cyan('underestimated')
          : chalk.yellow('overestimated'),
        entry.metric,
        chalk.gray('by'),
        Math.round(entry.diff),
        chalk.gray('on'),
        chalk.magenta(entry.url)
      );
    });
}

function findAndPrintFixesRegressions() {
  /** @type {Map<string, LanternEvaluation>} */
  const indexedByMetricURL = new Map();
  baselineEstimates.forEach(e => indexedByMetricURL.set(`${e.lanternMetric}${e.url}`, e));

  const joinedWithBaseline = estimates.map(actual => {
    const baseline = indexedByMetricURL.get(`${actual.lanternMetric}${actual.url}`);
    if (!baseline) return {...actual, regression: 0, regressionAsPercent: 0};
    const regression = actual.diff - baseline.diff;
    const regressionAsPercent = actual.diffAsPercent - baseline.diffAsPercent;
    return {...actual, baseline, regression, regressionAsPercent};
  });

  /** @param {LanternEvaluation} entry */
  const printEvaluation = entry => {
    console.log(
      entry.lanternMetric.replace('roughEstimateOf', ''),
      chalk.gray('on'),
      chalk.magenta(entry.url),
      '-',
      entry.expected,
      chalk.gray('(real)'),
      entry.actual,
      chalk.gray('(cur)'),
      // @ts-ignore - baseline always exists at this point
      entry.baseline.actual,
      chalk.gray('(prev)')
    );
  };

  console.log(chalk.bold('\n ------- Fixes Summary -------'));
  joinedWithBaseline
    .filter(e => e.regression < 0)
    .sort((a, b) => a.regressionAsPercent - b.regressionAsPercent)
    .slice(0, 4)
    .forEach(printEvaluation);
  console.log(chalk.bold('\n ------- Regression Summary -------'));
  joinedWithBaseline
    .filter(e => e.regression > 0)
    .sort((a, b) => b.regressionAsPercent - a.regressionAsPercent)
    .slice(0, 4)
    .forEach(printEvaluation);
}

console.log(
  chalk.bold(
    'Metric'.padEnd(25),
    'p50 (% Error)'.padEnd(20),
    'p90 (% Error)'.padEnd(20),
    'p95 (% Error)'.padEnd(20)
  )
);

evaluateAndPrintAccuracy('firstContentfulPaint', 'optimisticFCP');
evaluateAndPrintAccuracy('firstContentfulPaint', 'pessimisticFCP');
evaluateAndPrintAccuracy('firstContentfulPaint', 'roughEstimateOfFCP');

evaluateAndPrintAccuracy('firstMeaningfulPaint', 'optimisticFMP');
evaluateAndPrintAccuracy('firstMeaningfulPaint', 'pessimisticFMP');
evaluateAndPrintAccuracy('firstMeaningfulPaint', 'roughEstimateOfFMP');

evaluateAndPrintAccuracy('timeToFirstInteractive', 'optimisticTTFCPUI');
evaluateAndPrintAccuracy('timeToFirstInteractive', 'pessimisticTTFCPUI');
evaluateAndPrintAccuracy('timeToFirstInteractive', 'roughEstimateOfTTFCPUI');

evaluateAndPrintAccuracy('timeToConsistentlyInteractive', 'optimisticTTI');
evaluateAndPrintAccuracy('timeToConsistentlyInteractive', 'pessimisticTTI');
evaluateAndPrintAccuracy('timeToConsistentlyInteractive', 'roughEstimateOfTTI');

evaluateAndPrintAccuracy('speedIndex', 'optimisticSI');
evaluateAndPrintAccuracy('speedIndex', 'pessimisticSI');
evaluateAndPrintAccuracy('speedIndex', 'roughEstimateOfSI');

evaluateAndPrintAccuracy('largestContentfulPaint', 'optimisticLCP');
evaluateAndPrintAccuracy('largestContentfulPaint', 'pessimisticLCP');
evaluateAndPrintAccuracy('largestContentfulPaint', 'roughEstimateOfLCP');

const estimates = allEvaluations.filter(entry => entry.lanternMetric.includes('roughEstimate'));
const baselineEstimates = baselineEvaluations.filter(entry =>
  entry.lanternMetric.includes('roughEstimate')
);

findAndPrintWorst10Sites('firstContentfulPaint', [
  'optimisticFCP',
  'pessimisticFCP',
  'roughEstimateOfFCP',
]);
findAndPrintWorst10Sites('firstMeaningfulPaint', [
  'optimisticFMP',
  'pessimisticFMP',
  'roughEstimateOfFMP',
]);
findAndPrintWorst10Sites('timeToFirstInteractive', [
  'optimisticTTFCPUI',
  'pessimisticTTFCPUI',
  'roughEstimateOfTTFCPUI',
]);
findAndPrintWorst10Sites('timeToConsistentlyInteractive', [
  'optimisticTTI',
  'pessimisticTTI',
  'roughEstimateOfTTI',
]);
findAndPrintWorst10Sites('speedIndex', ['optimisticSI', 'pessimisticSI', 'roughEstimateOfSI']);
findAndPrintWorst10Sites('largestContentfulPaint', [
  'optimisticLCP',
  'pessimisticLCP',
  'roughEstimateOfLCP',
]);

findAndPrintFixesRegressions();

/**
 * @param {string} label
 * @param {(e: LanternEvaluation) => boolean} bucketFilterFn
 * @param {any} opts
 */
const printBucket = (label, bucketFilterFn, opts) => {
  const numInBucket = estimates.filter(bucketFilterFn).length;
  const baselineInBucket = baselineEstimates.filter(bucketFilterFn).length;

  const actual = numInBucket;
  const baseline = baselineInBucket;
  console.log(
    `${label}:`.padEnd(10),
    actual.toString().padEnd(5),
    // @ts-ignore - overly aggressive no implicit any
    toBaselineDiffString(actual, baseline, {...opts, format: x => x.toString()})
  );
};

console.log(chalk.bold('\n ------- Bucket Summary -------'));
printBucket('Good', isEvaluationGood, {isIncreaseGood: true});
printBucket('OK', isEvaluationOK, {alwaysGray: true});
printBucket('Bad', isEvaluationBad, {isIncreaseGood: false});

const percentErrors = estimates.map(x => x.diffAsPercent).sort((a, b) => a - b);
const baselinePercentErrors = baselineEstimates.map(x => x.diffAsPercent).sort((a, b) => a - b);

/** @param {number} percentile */
const printPercentile = percentile => {
  const index = Math.floor((percentErrors.length / 100) * percentile);
  const actual = percentErrors[index];
  const baseline = baselinePercentErrors[index];
  console.log(
    `p${percentile}:`.padEnd(10),
    toPercentString(actual),
    toBaselineDiffString(actual, baseline)
  );
};

console.log(chalk.bold('\n ------- % Error Summary -------'));
printPercentile(50);
printPercentile(90);
printPercentile(95);

if (constants.WARNINGS.length) {
  console.log('\n');
  for (const message of new Set(constants.WARNINGS)) {
    console.warn(chalk.yellowBright(message));
  }
}


text:
<?php
declare(strict_types=1);

namespace Markup\Contentful\Tests\Analysis;

use Markup\Contentful\Analysis\ResponseAnalysis;
use Markup\Contentful\Analysis\ResponseAnalysisInterface;
use PHPUnit\Framework\TestCase;

class ResponseAnalysisTest extends TestCase
{
    /**
     * @var int
     */
    private $responseCount;

    /**
     * @var bool
     */
    private $wasError;

    /**
     * @var ResponseAnalysis
     */
    private $analysis;

    protected function setUp()
    {
        $this->responseCount = 42;
        $this->wasError = true;
        $this->analysis = new ResponseAnalysis(
            $this->responseCount,
            $this->wasError
        );
    }

    public function testIsAnalysis()
    {
        $this->assertInstanceOf(ResponseAnalysisInterface::class, $this->analysis);
    }

    public function testGetters()
    {
        $this->assertEquals($this->responseCount, $this->analysis->getIndicatedResponseCount());
        $this->assertEquals($this->wasError, $this->analysis->indicatesError());
    }
}


text:
layout: doc
title: Manipulace s daty pomocí Osmosis
permalink: /cs/osm-data/osmosis/
lang: cs
category: osm-data
---

Manipulace s daty pomocí Osmosis
===============================

**Osmosis** je výkonný nástroj, ovládaný pomocí příkazové řádky, k manipulaci a zpracování surových **.osm** dat. Často se používá ke zpracování velkých datových souborů, pro rozdělování OSM souborů na menší části a pro aplikování sad změn na existující soubor.

Osmosis obsahuje spoustu skvělých funkcí a jejich detailní popis naleznete na [Wiki](http://wiki.openstreetmap.org/wiki/Osmosis/Detailed_Usage_0.41). Většinou se jedná o funkce poměrně komplexní a těžce pochopitelné, obzvláště pro začátečníky pracující s programy v příkazové řádce a OpenStreetMap. Tato kapitola vás seznámí s Osmosis, pomůže s intalací ve Windows a představí základní příkazy v Osmosis.

Instalace Osmosis
----------------

Stejně jako u osm2pgsql v předchozí kapitole, je potřeba stáhnout a nastavit **osmosis** tak, abychom jej mohli spustit pomocí příkazového řádku. Nastavení je podebné jako u osm2pgsql.

Budete taktéž potřebovat nějaká zdrojová data OSM, se kterými budete pracovat. Pokud chcete postuvat podle příkladu v této kapitole, stáhněte si náš ukázkový soubor [zde](/files/sample_osmosis.osm.pbf). Ale můžete si zvolit soubor dat dle vlastního výběru.

Pomocí následujících kroků si stáhněte a připravte Osmosis:

- Nejprve si [odsud](https://github.com/openstreetmap/osmosis/releases/latest) stáhněte Osmosis.
- Rozbalte adresář někam na disk, odkud už se nebude přesouvat. Je potřeba přidat umístění tohoto adresáře do systémové cesty, tak abychom jej mohli spustit z příkazové řádky.

![unzip it][]

- Klikněte na Start Menu a napište "proměnné prostředí."

![system path][]

- Měla by se vám zobrazit nastavení pojmenované "Upravit proměnné prostředí systému". Klikněte na něj.

![edit variables][]

- Klikněte na tlačítko "Proměnné prostředí".

![env variables][]

- Najděte proměnnou "Path" a klikněte na "Upravit..."

![find path][]

- Je potřeba přidat adresář, ve kterém je umístěný osmosis.bat.

![edit path][]

- /Windows 10/: Klikněte na tlačítko **Nový** a vložte celou cestu k adresáři Osmosis. (/Windows 7 a starší/: Přidejte středník na konec původního textu a pak vepište celou adresářovou cestu k osmosis.) Například, pokud jste uložili adresář **osmosis-latest** přímo na **C:\\**, potom cesta bude:

      C:\osmosis-latest\bin

- Klikněte na OK pro uložení nastavení.
- **osmosis** by mělo fungovat. Pojďme to zkontrolovat.
- Otevřeme si Příkazovou řádku ve Windows. Klikněte na vyhledávací tlačítko u nabídky Start a napište "**cmd**". Objeví se aplikace Příkazová řádka, tak na ni klikněte, nebo zmáčkněte Enter.

![cmd][]

- Jakmile se zobrazí černé okno, napište příkaz:

      osmosis

- Pokud vše správně funguje, měla by se vám zobrazit podobá zpráva:

![osmosis test][]

- Pokud tomu tak není a oznamuje vám to, že nemůže najít aplikaci **osmosis**, pak jste možná špatně zadali cestu k adresáři v proměnných prostředí.

Filtrování dat
---------------

Osmosis už by vám mělo běžet v příkazové řádce bez chyby. Abychom mohli provádět operace nad našimi daty, je potřeba změnit umístění pracovního adresáře na místo, kam jsme umístili soubor **sample_osmosis.osm.pbf**. Abychom to zjednodušili, umístili jsme soubor do **C:\ directory**.

- V příkazové řádce toto nastavení provedete pomocí následujícího příkazu. Napište ho a zmáčkněte Enter:

      cd C:\

- Text v řádku by se měl změnit, indikuje nyní, že jste v adresáři C:\. (Pokud se tak nestalo, zkuste příkazový řádek spustit jako správce).

![cd command][]

Teď se naučíme náš první příkaz v Osmosis. Ten nám vyfiltruje všechny školy z našeho velkého souboru.

Aby se tak stalo, musíme Osmosis sdělit několik věcí. Je potřeba specifikovat:

- zdrojový soubor (sample_osmosis.osm.pbf)
- několik pravidel, podle kterých se bude filtrovat
- výstupní soubor (vytvoří se nekomprimovaný .osm soubor, který lze otevřít v JOSM)

Příkaz ke spuštění zní:

      osmosis --rbf sample_osmosis.osm.pbf --nkv keyValueList="amenity.school" --wx schools.osm

Zkuste jej spustit v příkazové řádce. Jakmile se proces dokončí, měli bychom mít ve výstupním adresáři nový soubor **schools.osm**. Když jej otevřeme pomocí JOSM, z původní mapy se nám zobrazí pouze školy.

![schools osm][]

Popišme si příkaz krok po kroku, abychom pochopili, jak funguje. Na prvním místě je název programu.

      osmosis

Následuje zdrojový soubor. Pamatujete si, že tento soubor je komprimovaný formát. **--rbg** je zkratka pro **--read-pbf-fast**. Osmosis tomu rozumí tak, že soubor následující za tímto příkazem je ten, ze kterého chceme načíst data.

      --rbf sample_osmosis.osm.pbf

Další kousek našeho příkazu říká *--nkv keyValueList="amenity.school"*. Nejspíš jste uhodli, že osmosis má vyfiltrovat všechno s tagem (zančkou) **amenity=school**. **--nkv** je zkratka pro **--node-key-value**. Což znamená, že by Osmosis mělo vybrat pouze body s kombinaci klíčů a hodnot uvedených v následujícím seznamu. Další kombinace key.value oddělte čarkami.

      --nkv keyValueList="amenity.school"

Nakonec zadáme jméno a formát výstupního souboru. Použijeme zkratku **--wx**, která znamená **--write-xml**. Jde použít i **--wb**, což je protějšek pro **--rbf**, pokud chcete výstupní data opět ve formátu PBF.

      --wx schools.osm

Pokračujeme dál
---------------

Množství úkolů, které můžeme provádět pomocí Osmosis je obrovské a pokud je chcete více prozkoumat mrkněte na stránku [Osmosis Detailed Usage](http://wiki.openstreetmap.org/wiki/Osmosis/Detailed_Usage_0.43)(anglicky) na Wiki.

Jeden příkaz může rozdělit velký zdrojový OSM soubor na menší části, ať už podle definovaných čtverců nebo ohraničujících polygonů. Základní informace se o tomto tématu můžete dozvědět na [stránce s přiklady v Osmosis](http://wiki.openstreetmap.org/wiki/Osmosis/Examples)(anglicky).

[unzip it]: /images/osm-data/unzip-it.png
[system path]: /images/osm-data/system-path_cs.png
[edit variables]: /images/osm-data/edit-environment-variables_cs.png
[env variables]: /images/osm-data/environment-variables_cs.png
[find path]: /images/osm-data/find-path_cs.png
[edit path]: /images/osm-data/edit-path-variable_cs.png
[cmd]: /images/osm-data/cmd.png
[osmosis test]: /images/osm-data/osmosis-test.png
[cd command]: /images/osm-data/cd-command.png
[schools osm]: /images/osm-data/schools-osm.png


text:
package DMOZ::CategorySignatures::GraphSignature;

use strict;
use warnings;

use Moose;
use namespace::autoclean;

extends( 'DMOZ::CategorySignatures' );

__PACKAGE__->meta->make_immutable;

1;


text:
/**
 * The Testability service provides testing hooks that can be accessed from
 * the browser and by services such as Protractor. Each bootstrapped Angular
 * application on the page will have an instance of Testability.
 */
export declare class Testability {
    _pendingCount: number;
    _callbacks: List<Function>;
    constructor();
    increaseCount(delta?: number): number;
    _runCallbacks(): void;
    whenStable(callback: Function): void;
    getPendingCount(): number;
    findBindings(using: any, binding: string, exactMatch: boolean): List<any>;
}
export declare class TestabilityRegistry {
    _applications: Map<any, Testability>;
    constructor();
    registerApplication(token: any, testability: Testability): void;
    findTestabilityInTree(elem: any): Testability;
}
export declare var __esModule: boolean;


text:
{% extends "base.html" %}
{% load staticfiles %}

{% block css %}
<link href="{% static 'css/progress.css' %}" rel="stylesheet" media="screen">
{% endblock %}

{% block js %}

{% endblock %}

{% block content %}

輕鬆、快速的取得你所需要的零件

                    Photo by Jeff Keyzer on Flickr

使用最新最棒的零件進行創作

                    Photo by Windell Oskay on Flickr

以低廉的運費取得正廠零件

                    Photo by Gwan Kho on Flickr

            Previous

            Next

Digikey集單進度

            {% verbatim %}

                集單目標
                $3000

                已集單價格
                {{ current_accumulated | currency }}

                已完成
                {{ current_percent }}%

                參與人數
                {{ current_person_count }}

            {% endverbatim %}

            <button id="go-button" type="button" class="btn btn-success" ng-click="go_order()">馬上參加集單</button>

{% endblock %}


text:
module ApplicationHelper
  def submit_button_name(model)
    model.new_record? ? '作成' : '更新'
  end
end


text: <img src = "https://mp.weixin.qq.com/cgi-bin/showqrcode?ticket={{qrcode}}" style="width:250px" />