<commit_before>// $Id$

/**************************************************************************
 * This file is property of and copyright by the ALICE HLT Project        *
 * ALICE Experiment at CERN, All rights reserved.                         *
 *                                                                        *
 * Primary Authors: Matthias Richter <Matthias.Richter@ift.uib.no>        *
 *                  Timm Steinbeck <timm@kip.uni-heidelberg.de>           *
 *                  for The ALICE HLT Project.                            *
 *                                                                        *
 * Permission to use, copy, modify and distribute this software and its   *
 * documentation strictly for non-commercial purposes is hereby granted   *
 * without fee, provided that the above copyright notice appears in all   *
 * copies and that both the copyright notice and this permission notice   *
 * appear in the supporting documentation. The authors make no claims     *
 * about the suitability of this software for any purpose. It is          *
 * provided "as is" without express or implied warranty.                  *
 **************************************************************************/

///////////////////////////////////////////////////////////////////////////////
//                                                                           //
// Definitions for the HLT TPC components                                    //
//                                                                           //
///////////////////////////////////////////////////////////////////////////////

#include "AliHLTTPCDefinitions.h"
#include "AliHLTTPCGeometry.h"
#include <cerrno>

/** ROOT macro for the implementation of ROOT specific class methods */
ClassImp(AliHLTTPCDefinitions)

const AliHLTComponentDataType AliHLTTPCDefinitions::fgkDDLEncodedEntropyRawDataType = AliHLTComponentDataTypeInitializer("DDLENCEN", kAliHLTDataOriginTPC);

const AliHLTComponentDataType AliHLTTPCDefinitions::fgkPackedRawDataType = AliHLTComponentDataTypeInitializer("RAWPAKED", kAliHLTDataOriginTPC);
const AliHLTComponentDataType AliHLTTPCDefinitions::fgkUnpackedRawDataType = AliHLTComponentDataTypeInitializer("RAWUNPAK", kAliHLTDataOriginTPC);
const AliHLTComponentDataType AliHLTTPCDefinitions::fgkClustersDataType = AliHLTComponentDataTypeInitializer("CLUSTERS", kAliHLTDataOriginTPC);
const AliHLTComponentDataType AliHLTTPCDefinitions::fgkRawClustersDataType = AliHLTComponentDataTypeInitializer("CLUSTRAW", kAliHLTDataOriginTPC);
const AliHLTComponentDataType AliHLTTPCDefinitions::fgkRawClustersDataTypeNotCompressed = AliHLTComponentDataTypeInitializer("CLUSNOTC", kAliHLTDataOriginTPC);
const AliHLTComponentDataType AliHLTTPCDefinitions::fgkRawClustersDescriptorDataType = AliHLTComponentDataTypeInitializer("CLRAWDSC", kAliHLTDataOriginTPC);
const AliHLTComponentDataType AliHLTTPCDefinitions::fgkHWClustersDataType = AliHLTComponentDataTypeInitializer("HWCLUST1", kAliHLTDataOriginTPC);
const AliHLTComponentDataType AliHLTTPCDefinitions::fgkAlterClustersDataType = AliHLTComponentDataTypeInitializer("HWCL_ALT", kAliHLTDataOriginTPC);
const AliHLTComponentDataType AliHLTTPCDefinitions::fgkVertexDataType = AliHLTComponentDataTypeInitializer("VERTEX  ", kAliHLTDataOriginTPC);
const AliHLTComponentDataType AliHLTTPCDefinitions::fgkTrackSegmentsDataType = AliHLTComponentDataTypeInitializer("TRAKSEGS", kAliHLTDataOriginTPC);
const AliHLTComponentDataType AliHLTTPCDefinitions::fgkTracksDataType = AliHLTComponentDataTypeInitializer("TRACKS  ", kAliHLTDataOriginTPC);

const AliHLTComponentDataType AliHLTTPCDefinitions::fgkDataCompressionDescriptorDataType = AliHLTComponentDataTypeInitializer("COMPDESC", kAliHLTDataOriginTPC);
const AliHLTComponentDataType AliHLTTPCDefinitions::fgkClusterTracksModelDataType = AliHLTComponentDataTypeInitializer("CLSTRKMD", kAliHLTDataOriginTPC);
const AliHLTComponentDataType AliHLTTPCDefinitions::fgkRemainingClustersModelDataType = AliHLTComponentDataTypeInitializer("REMCLSMD", kAliHLTDataOriginTPC);
const AliHLTComponentDataType AliHLTTPCDefinitions::fgkClusterTracksCompressedDataType = AliHLTComponentDataTypeInitializer("CLSTRKCM", kAliHLTDataOriginTPC);
const AliHLTComponentDataType AliHLTTPCDefinitions::fgkRemainingClustersCompressedDataType = AliHLTComponentDataTypeInitializer("REMCLSCM", kAliHLTDataOriginTPC);
const AliHLTComponentDataType AliHLTTPCDefinitions::fgkTPCFastTransformDataObjectDataType = AliHLTComponentDataTypeInitializer("HLTTPCFT", kAliHLTDataOriginTPC);

const AliHLTComponentDataType& AliHLTTPCDefinitions::DDLEncodedEntropyRawDataType() {
  static AliHLTComponentDataType dt = AliHLTComponentDataTypeInitializer("DDLENCEN", kAliHLTDataOriginTPC);
  return dt;
}
const AliHLTComponentDataType& AliHLTTPCDefinitions::PackedRawDataType() {
  static AliHLTComponentDataType dt = AliHLTComponentDataTypeInitializer("RAWPAKED", kAliHLTDataOriginTPC);
  return dt;
}
const AliHLTComponentDataType& AliHLTTPCDefinitions::UnpackedRawDataType() {
  static AliHLTComponentDataType dt = AliHLTComponentDataTypeInitializer("RAWUNPAK", kAliHLTDataOriginTPC);
  return dt;
}
const AliHLTComponentDataType& AliHLTTPCDefinitions::ClustersDataType() {
  static AliHLTComponentDataType dt = AliHLTComponentDataTypeInitializer("CLUSTERS", kAliHLTDataOriginTPC);
  return dt;
}
const AliHLTComponentDataType& AliHLTTPCDefinitions::RawClustersDataType() {
  static AliHLTComponentDataType dt = AliHLTComponentDataTypeInitializer("CLUSTRAW", kAliHLTDataOriginTPC);
  return dt;
}
const AliHLTComponentDataType& AliHLTTPCDefinitions::RawClustersDataTypeNotCompressed() {
  static AliHLTComponentDataType dt = AliHLTComponentDataTypeInitializer("CLUSOTC", kAliHLTDataOriginTPC);
  return dt;
}
const AliHLTComponentDataType& AliHLTTPCDefinitions::RawClustersDescriptorDataType() {
  static AliHLTComponentDataType dt = AliHLTComponentDataTypeInitializer("CLRAWDSC", kAliHLTDataOriginTPC);
  return dt;
}
const AliHLTComponentDataType& AliHLTTPCDefinitions::HWClustersDataType() {
  static AliHLTComponentDataType dt = AliHLTComponentDataTypeInitializer("HWCLUST1", kAliHLTDataOriginTPC);
  return dt;
}
const AliHLTComponentDataType& AliHLTTPCDefinitions::AlterClustersDataType() {
  static AliHLTComponentDataType dt = AliHLTComponentDataTypeInitializer("HWCL_ALT", kAliHLTDataOriginTPC);
  return dt;
}
const AliHLTComponentDataType& AliHLTTPCDefinitions::VertexDataType() {
  static AliHLTComponentDataType dt = AliHLTComponentDataTypeInitializer("VERTEX  ", kAliHLTDataOriginTPC);
  return dt;
}
const AliHLTComponentDataType& AliHLTTPCDefinitions::TrackSegmentsDataType() {
  static AliHLTComponentDataType dt = AliHLTComponentDataTypeInitializer("TRAKSEGS", kAliHLTDataOriginTPC);
  return dt;
}
const AliHLTComponentDataType& AliHLTTPCDefinitions::TracksDataType() {
  static AliHLTComponentDataType dt = AliHLTComponentDataTypeInitializer("TRACKS  ", kAliHLTDataOriginTPC);
  return dt;
}
const AliHLTComponentDataType& AliHLTTPCDefinitions::DataCompressionDescriptorDataType() {
  static AliHLTComponentDataType dt = AliHLTComponentDataTypeInitializer("COMPDESC", kAliHLTDataOriginTPC);
  return dt;
}
const AliHLTComponentDataType& AliHLTTPCDefinitions::ClusterTracksModelDataType() {
  static AliHLTComponentDataType dt = AliHLTComponentDataTypeInitializer("CLSTRKMD", kAliHLTDataOriginTPC);
  return dt;
}
const AliHLTComponentDataType& AliHLTTPCDefinitions::RemainingClustersModelDataType() {
  static AliHLTComponentDataType dt = AliHLTComponentDataTypeInitializer("REMCLSMD", kAliHLTDataOriginTPC);
  return dt;
}
const AliHLTComponentDataType& AliHLTTPCDefinitions::ClusterTracksCompressedDataType() {
  static AliHLTComponentDataType dt = AliHLTComponentDataTypeInitializer("CLSTRKCM", kAliHLTDataOriginTPC);
  return dt;
}
const AliHLTComponentDataType& AliHLTTPCDefinitions::ClusterIdTracksDataType() {
  static AliHLTComponentDataType dt = AliHLTComponentDataTypeInitializer("CLIDSTRK", kAliHLTDataOriginTPC);
  return dt;
}
const AliHLTComponentDataType& AliHLTTPCDefinitions::CompressedClusterIdDataType() {
  static AliHLTComponentDataType dt = AliHLTComponentDataTypeInitializer("COMPCLID", kAliHLTDataOriginTPC);
  return dt;
}
const AliHLTComponentDataType& AliHLTTPCDefinitions::RemainingClustersCompressedDataType() {
  static AliHLTComponentDataType dt = AliHLTComponentDataTypeInitializer("REMCLSCM", kAliHLTDataOriginTPC);
  return dt;
}
const AliHLTComponentDataType& AliHLTTPCDefinitions::RemainingClusterIdsDataType() {
  static AliHLTComponentDataType dt = AliHLTComponentDataTypeInitializer("REMCLIDS", kAliHLTDataOriginTPC);
  return dt;
}

const AliHLTComponentDataType& AliHLTTPCDefinitions::CalibPedestalDataType() {
  static AliHLTComponentDataType dt = AliHLTComponentDataTypeInitializer("CAL_PED ", kAliHLTDataOriginTPC);
  return dt;
}
const AliHLTComponentDataType& AliHLTTPCDefinitions::CalibPulserDataType() {
  static AliHLTComponentDataType dt = AliHLTComponentDataTypeInitializer("CAL_PULS", kAliHLTDataOriginTPC);
  return dt;
}
const AliHLTComponentDataType& AliHLTTPCDefinitions::CalibCEDataType() {
  static AliHLTComponentDataType dt = AliHLTComponentDataTypeInitializer("CAL_CE  ", kAliHLTDataOriginTPC);
  return dt;
}

const AliHLTComponentDataType& AliHLTTPCDefinitions::OfflineCalibAlignDataType() {
  static AliHLTComponentDataType dt = AliHLTComponentDataTypeInitializer("CALALIGN", kAliHLTDataOriginTPC);
  return dt;
}
const AliHLTComponentDataType& AliHLTTPCDefinitions::OfflineCalibTracksDataType() {
  static AliHLTComponentDataType dt = AliHLTComponentDataTypeInitializer("CALTRACK", kAliHLTDataOriginTPC);
  return dt;
}

const AliHLTComponentDataType& AliHLTTPCDefinitions::OfflineCalibTracksGainDataType() {
  static AliHLTComponentDataType dt = AliHLTComponentDataTypeInitializer("CALGAIN ", kAliHLTDataOriginTPC);
  return dt;
}

const AliHLTComponentDataType& AliHLTTPCDefinitions::AliHLTDataTypeClusterMCInfo() {
  static AliHLTComponentDataType dt = AliHLTComponentDataTypeInitializer("CLMCINFO", kAliHLTDataOriginTPC);
  return dt;
}
const AliHLTComponentDataType AliHLTTPCDefinitions::fgkAliHLTDataTypeClusterMCInfo = AliHLTComponentDataTypeInitializer("CLMCINFO", kAliHLTDataOriginTPC);

const AliHLTTPCDefinitions::AliClusterParameter AliHLTTPCDefinitions::fgkClusterParameterDefinitions[]= {
  {AliHLTTPCDefinitions::kPadRow,  "padrow",   6,  1,   1}, // difference of rows, mostly 0 or 1
  {AliHLTTPCDefinitions::kPad,     "pad",     14, 12,  60}, // <100um for 6mm pads
  {AliHLTTPCDefinitions::kTime,    "time",    15, 13,  25}, // <100um for 2.5 mm timebin pitch
  {AliHLTTPCDefinitions::kSigmaY2, "sigmaY2",  8,  5,  25},
  {AliHLTTPCDefinitions::kSigmaZ2, "sigmaZ2",  8,  5,  10},
  {AliHLTTPCDefinitions::kCharge,  "charge",  16,  9,   1},
  {AliHLTTPCDefinitions::kQMax,    "qmax",    10,  6,   1},
  {AliHLTTPCDefinitions::kResidualPad, "respad",         9,  4, 60}, // <100um for 6mm pads, sign stored in separate bit
  {AliHLTTPCDefinitions::kResidualTime,"restime",        8,  4, 25}, // <100um for 2.5 mm timebin pitch, separate bit for sign
  {AliHLTTPCDefinitions::kClusterCount,"clustercount",   6,  3,  1}  // number of clusters on that row
};

unsigned AliHLTTPCDefinitions::GetNumberOfClusterParameterDefinitions()
{
  return sizeof(fgkClusterParameterDefinitions)/sizeof(AliClusterParameter);
}

// NOTE! those values are related to the number of bits in
// fgkClusterParameterDefinitions
const unsigned AliHLTTPCDefinitions::fgkMaxClusterDeltaPad=8;
const unsigned AliHLTTPCDefinitions::fgkMaxClusterDeltaTime=10;

AliHLTTPCDefinitions::AliHLTTPCDefinitions()
{
  // see header file for class documentation
  // or
  // refer to README to build package
  // or
  // visit http://web.ift.uib.no/~kjeks/doc/alice-hlt
}

AliHLTTPCDefinitions::~AliHLTTPCDefinitions()
{
  // see header file for class documentation
}

bool AliHLTTPCDefinitions::DDLIdToSlicePatch(AliHLTInt32_t ddlid, AliHLTUInt8_t& slice, AliHLTUInt8_t& patch)
{
	// Convert DDL ID to patch and slice numbers.

	if ((AliHLTUInt32_t(ddlid) >> 8) != 0x3) return false;  // Check that detector is TPC.
	AliHLTUInt32_t ddl = (AliHLTUInt32_t(ddlid) & 0xFF);
	if (ddl > 215) return false;
	if (ddl < 72)
	{
		slice = ddl / 2;
		patch = ddl % 2;
	}
	else
	{
		ddl -= 72;
		slice = ddl / 4;
		patch = ddl % 4 + 2;
	}
	return true;
}

Int_t AliHLTTPCDefinitions::GetSingleSliceNr( ULong_t spec )
{
  // get the slice number provided that spec encodes a single slice
  // return -EINVAL if encoded min and max slice differ
  // return -ERANGE if slice number out of range
  AliHLTUInt8_t min=GetMinSliceNr(spec);
  AliHLTUInt8_t max=GetMaxSliceNr(spec);
  if (min!=max) return -EINVAL;
  if (max>=AliHLTTPCGeometry::GetNSlice()) return -ERANGE;
  return min;
}

Int_t AliHLTTPCDefinitions::GetSinglePatchNr( ULong_t spec )
{
  // get the patch number provided that spec encodes a single patch
  // return -EINVAL if encoded min and max patch differ
  // return -ERANGE if patch number out of range
  AliHLTUInt8_t min=GetMinPatchNr(spec);
  AliHLTUInt8_t max=GetMaxPatchNr(spec);
  if (min!=max) return -EINVAL;
  if (max>=AliHLTTPCGeometry::GetNumberOfPatches()) return -ERANGE;
  return min;
}
<commit_msg>fix typo<commit_after>// $Id$

/**************************************************************************
 * This file is property of and copyright by the ALICE HLT Project        *
 * ALICE Experiment at CERN, All rights reserved.                         *
 *                                                                        *
 * Primary Authors: Matthias Richter <Matthias.Richter@ift.uib.no>        *
 *                  Timm Steinbeck <timm@kip.uni-heidelberg.de>           *
 *                  for The ALICE HLT Project.                            *
 *                                                                        *
 * Permission to use, copy, modify and distribute this software and its   *
 * documentation strictly for non-commercial purposes is hereby granted   *
 * without fee, provided that the above copyright notice appears in all   *
 * copies and that both the copyright notice and this permission notice   *
 * appear in the supporting documentation. The authors make no claims     *
 * about the suitability of this software for any purpose. It is          *
 * provided "as is" without express or implied warranty.                  *
 **************************************************************************/

///////////////////////////////////////////////////////////////////////////////
//                                                                           //
// Definitions for the HLT TPC components                                    //
//                                                                           //
///////////////////////////////////////////////////////////////////////////////

#include "AliHLTTPCDefinitions.h"
#include "AliHLTTPCGeometry.h"
#include <cerrno>

/** ROOT macro for the implementation of ROOT specific class methods */
ClassImp(AliHLTTPCDefinitions)

const AliHLTComponentDataType AliHLTTPCDefinitions::fgkDDLEncodedEntropyRawDataType = AliHLTComponentDataTypeInitializer("DDLENCEN", kAliHLTDataOriginTPC);

const AliHLTComponentDataType AliHLTTPCDefinitions::fgkPackedRawDataType = AliHLTComponentDataTypeInitializer("RAWPAKED", kAliHLTDataOriginTPC);
const AliHLTComponentDataType AliHLTTPCDefinitions::fgkUnpackedRawDataType = AliHLTComponentDataTypeInitializer("RAWUNPAK", kAliHLTDataOriginTPC);
const AliHLTComponentDataType AliHLTTPCDefinitions::fgkClustersDataType = AliHLTComponentDataTypeInitializer("CLUSTERS", kAliHLTDataOriginTPC);
const AliHLTComponentDataType AliHLTTPCDefinitions::fgkRawClustersDataType = AliHLTComponentDataTypeInitializer("CLUSTRAW", kAliHLTDataOriginTPC);
const AliHLTComponentDataType AliHLTTPCDefinitions::fgkRawClustersDataTypeNotCompressed = AliHLTComponentDataTypeInitializer("CLUSNOTC", kAliHLTDataOriginTPC);
const AliHLTComponentDataType AliHLTTPCDefinitions::fgkRawClustersDescriptorDataType = AliHLTComponentDataTypeInitializer("CLRAWDSC", kAliHLTDataOriginTPC);
const AliHLTComponentDataType AliHLTTPCDefinitions::fgkHWClustersDataType = AliHLTComponentDataTypeInitializer("HWCLUST1", kAliHLTDataOriginTPC);
const AliHLTComponentDataType AliHLTTPCDefinitions::fgkAlterClustersDataType = AliHLTComponentDataTypeInitializer("HWCL_ALT", kAliHLTDataOriginTPC);
const AliHLTComponentDataType AliHLTTPCDefinitions::fgkVertexDataType = AliHLTComponentDataTypeInitializer("VERTEX  ", kAliHLTDataOriginTPC);
const AliHLTComponentDataType AliHLTTPCDefinitions::fgkTrackSegmentsDataType = AliHLTComponentDataTypeInitializer("TRAKSEGS", kAliHLTDataOriginTPC);
const AliHLTComponentDataType AliHLTTPCDefinitions::fgkTracksDataType = AliHLTComponentDataTypeInitializer("TRACKS  ", kAliHLTDataOriginTPC);

const AliHLTComponentDataType AliHLTTPCDefinitions::fgkDataCompressionDescriptorDataType = AliHLTComponentDataTypeInitializer("COMPDESC", kAliHLTDataOriginTPC);
const AliHLTComponentDataType AliHLTTPCDefinitions::fgkClusterTracksModelDataType = AliHLTComponentDataTypeInitializer("CLSTRKMD", kAliHLTDataOriginTPC);
const AliHLTComponentDataType AliHLTTPCDefinitions::fgkRemainingClustersModelDataType = AliHLTComponentDataTypeInitializer("REMCLSMD", kAliHLTDataOriginTPC);
const AliHLTComponentDataType AliHLTTPCDefinitions::fgkClusterTracksCompressedDataType = AliHLTComponentDataTypeInitializer("CLSTRKCM", kAliHLTDataOriginTPC);
const AliHLTComponentDataType AliHLTTPCDefinitions::fgkRemainingClustersCompressedDataType = AliHLTComponentDataTypeInitializer("REMCLSCM", kAliHLTDataOriginTPC);
const AliHLTComponentDataType AliHLTTPCDefinitions::fgkTPCFastTransformDataObjectDataType = AliHLTComponentDataTypeInitializer("HLTTPCFT", kAliHLTDataOriginTPC);

const AliHLTComponentDataType& AliHLTTPCDefinitions::DDLEncodedEntropyRawDataType() {
  static AliHLTComponentDataType dt = AliHLTComponentDataTypeInitializer("DDLENCEN", kAliHLTDataOriginTPC);
  return dt;
}
const AliHLTComponentDataType& AliHLTTPCDefinitions::PackedRawDataType() {
  static AliHLTComponentDataType dt = AliHLTComponentDataTypeInitializer("RAWPAKED", kAliHLTDataOriginTPC);
  return dt;
}
const AliHLTComponentDataType& AliHLTTPCDefinitions::UnpackedRawDataType() {
  static AliHLTComponentDataType dt = AliHLTComponentDataTypeInitializer("RAWUNPAK", kAliHLTDataOriginTPC);
  return dt;
}
const AliHLTComponentDataType& AliHLTTPCDefinitions::ClustersDataType() {
  static AliHLTComponentDataType dt = AliHLTComponentDataTypeInitializer("CLUSTERS", kAliHLTDataOriginTPC);
  return dt;
}
const AliHLTComponentDataType& AliHLTTPCDefinitions::RawClustersDataType() {
  static AliHLTComponentDataType dt = AliHLTComponentDataTypeInitializer("CLUSTRAW", kAliHLTDataOriginTPC);
  return dt;
}
const AliHLTComponentDataType& AliHLTTPCDefinitions::RawClustersDataTypeNotCompressed() {
  static AliHLTComponentDataType dt = AliHLTComponentDataTypeInitializer("CLUSNOTC", kAliHLTDataOriginTPC);
  return dt;
}
const AliHLTComponentDataType& AliHLTTPCDefinitions::RawClustersDescriptorDataType() {
  static AliHLTComponentDataType dt = AliHLTComponentDataTypeInitializer("CLRAWDSC", kAliHLTDataOriginTPC);
  return dt;
}
const AliHLTComponentDataType& AliHLTTPCDefinitions::HWClustersDataType() {
  static AliHLTComponentDataType dt = AliHLTComponentDataTypeInitializer("HWCLUST1", kAliHLTDataOriginTPC);
  return dt;
}
const AliHLTComponentDataType& AliHLTTPCDefinitions::AlterClustersDataType() {
  static AliHLTComponentDataType dt = AliHLTComponentDataTypeInitializer("HWCL_ALT", kAliHLTDataOriginTPC);
  return dt;
}
const AliHLTComponentDataType& AliHLTTPCDefinitions::VertexDataType() {
  static AliHLTComponentDataType dt = AliHLTComponentDataTypeInitializer("VERTEX  ", kAliHLTDataOriginTPC);
  return dt;
}
const AliHLTComponentDataType& AliHLTTPCDefinitions::TrackSegmentsDataType() {
  static AliHLTComponentDataType dt = AliHLTComponentDataTypeInitializer("TRAKSEGS", kAliHLTDataOriginTPC);
  return dt;
}
const AliHLTComponentDataType& AliHLTTPCDefinitions::TracksDataType() {
  static AliHLTComponentDataType dt = AliHLTComponentDataTypeInitializer("TRACKS  ", kAliHLTDataOriginTPC);
  return dt;
}
const AliHLTComponentDataType& AliHLTTPCDefinitions::DataCompressionDescriptorDataType() {
  static AliHLTComponentDataType dt = AliHLTComponentDataTypeInitializer("COMPDESC", kAliHLTDataOriginTPC);
  return dt;
}
const AliHLTComponentDataType& AliHLTTPCDefinitions::ClusterTracksModelDataType() {
  static AliHLTComponentDataType dt = AliHLTComponentDataTypeInitializer("CLSTRKMD", kAliHLTDataOriginTPC);
  return dt;
}
const AliHLTComponentDataType& AliHLTTPCDefinitions::RemainingClustersModelDataType() {
  static AliHLTComponentDataType dt = AliHLTComponentDataTypeInitializer("REMCLSMD", kAliHLTDataOriginTPC);
  return dt;
}
const AliHLTComponentDataType& AliHLTTPCDefinitions::ClusterTracksCompressedDataType() {
  static AliHLTComponentDataType dt = AliHLTComponentDataTypeInitializer("CLSTRKCM", kAliHLTDataOriginTPC);
  return dt;
}
const AliHLTComponentDataType& AliHLTTPCDefinitions::ClusterIdTracksDataType() {
  static AliHLTComponentDataType dt = AliHLTComponentDataTypeInitializer("CLIDSTRK", kAliHLTDataOriginTPC);
  return dt;
}
const AliHLTComponentDataType& AliHLTTPCDefinitions::CompressedClusterIdDataType() {
  static AliHLTComponentDataType dt = AliHLTComponentDataTypeInitializer("COMPCLID", kAliHLTDataOriginTPC);
  return dt;
}
const AliHLTComponentDataType& AliHLTTPCDefinitions::RemainingClustersCompressedDataType() {
  static AliHLTComponentDataType dt = AliHLTComponentDataTypeInitializer("REMCLSCM", kAliHLTDataOriginTPC);
  return dt;
}
const AliHLTComponentDataType& AliHLTTPCDefinitions::RemainingClusterIdsDataType() {
  static AliHLTComponentDataType dt = AliHLTComponentDataTypeInitializer("REMCLIDS", kAliHLTDataOriginTPC);
  return dt;
}

const AliHLTComponentDataType& AliHLTTPCDefinitions::CalibPedestalDataType() {
  static AliHLTComponentDataType dt = AliHLTComponentDataTypeInitializer("CAL_PED ", kAliHLTDataOriginTPC);
  return dt;
}
const AliHLTComponentDataType& AliHLTTPCDefinitions::CalibPulserDataType() {
  static AliHLTComponentDataType dt = AliHLTComponentDataTypeInitializer("CAL_PULS", kAliHLTDataOriginTPC);
  return dt;
}
const AliHLTComponentDataType& AliHLTTPCDefinitions::CalibCEDataType() {
  static AliHLTComponentDataType dt = AliHLTComponentDataTypeInitializer("CAL_CE  ", kAliHLTDataOriginTPC);
  return dt;
}

const AliHLTComponentDataType& AliHLTTPCDefinitions::OfflineCalibAlignDataType() {
  static AliHLTComponentDataType dt = AliHLTComponentDataTypeInitializer("CALALIGN", kAliHLTDataOriginTPC);
  return dt;
}
const AliHLTComponentDataType& AliHLTTPCDefinitions::OfflineCalibTracksDataType() {
  static AliHLTComponentDataType dt = AliHLTComponentDataTypeInitializer("CALTRACK", kAliHLTDataOriginTPC);
  return dt;
}

const AliHLTComponentDataType& AliHLTTPCDefinitions::OfflineCalibTracksGainDataType() {
  static AliHLTComponentDataType dt = AliHLTComponentDataTypeInitializer("CALGAIN ", kAliHLTDataOriginTPC);
  return dt;
}

const AliHLTComponentDataType& AliHLTTPCDefinitions::AliHLTDataTypeClusterMCInfo() {
  static AliHLTComponentDataType dt = AliHLTComponentDataTypeInitializer("CLMCINFO", kAliHLTDataOriginTPC);
  return dt;
}
const AliHLTComponentDataType AliHLTTPCDefinitions::fgkAliHLTDataTypeClusterMCInfo = AliHLTComponentDataTypeInitializer("CLMCINFO", kAliHLTDataOriginTPC);

const AliHLTTPCDefinitions::AliClusterParameter AliHLTTPCDefinitions::fgkClusterParameterDefinitions[]= {
  {AliHLTTPCDefinitions::kPadRow,  "padrow",   6,  1,   1}, // difference of rows, mostly 0 or 1
  {AliHLTTPCDefinitions::kPad,     "pad",     14, 12,  60}, // <100um for 6mm pads
  {AliHLTTPCDefinitions::kTime,    "time",    15, 13,  25}, // <100um for 2.5 mm timebin pitch
  {AliHLTTPCDefinitions::kSigmaY2, "sigmaY2",  8,  5,  25},
  {AliHLTTPCDefinitions::kSigmaZ2, "sigmaZ2",  8,  5,  10},
  {AliHLTTPCDefinitions::kCharge,  "charge",  16,  9,   1},
  {AliHLTTPCDefinitions::kQMax,    "qmax",    10,  6,   1},
  {AliHLTTPCDefinitions::kResidualPad, "respad",         9,  4, 60}, // <100um for 6mm pads, sign stored in separate bit
  {AliHLTTPCDefinitions::kResidualTime,"restime",        8,  4, 25}, // <100um for 2.5 mm timebin pitch, separate bit for sign
  {AliHLTTPCDefinitions::kClusterCount,"clustercount",   6,  3,  1}  // number of clusters on that row
};

unsigned AliHLTTPCDefinitions::GetNumberOfClusterParameterDefinitions()
{
  return sizeof(fgkClusterParameterDefinitions)/sizeof(AliClusterParameter);
}

// NOTE! those values are related to the number of bits in
// fgkClusterParameterDefinitions
const unsigned AliHLTTPCDefinitions::fgkMaxClusterDeltaPad=8;
const unsigned AliHLTTPCDefinitions::fgkMaxClusterDeltaTime=10;

AliHLTTPCDefinitions::AliHLTTPCDefinitions()
{
  // see header file for class documentation
  // or
  // refer to README to build package
  // or
  // visit http://web.ift.uib.no/~kjeks/doc/alice-hlt
}

AliHLTTPCDefinitions::~AliHLTTPCDefinitions()
{
  // see header file for class documentation
}

bool AliHLTTPCDefinitions::DDLIdToSlicePatch(AliHLTInt32_t ddlid, AliHLTUInt8_t& slice, AliHLTUInt8_t& patch)
{
	// Convert DDL ID to patch and slice numbers.

	if ((AliHLTUInt32_t(ddlid) >> 8) != 0x3) return false;  // Check that detector is TPC.
	AliHLTUInt32_t ddl = (AliHLTUInt32_t(ddlid) & 0xFF);
	if (ddl > 215) return false;
	if (ddl < 72)
	{
		slice = ddl / 2;
		patch = ddl % 2;
	}
	else
	{
		ddl -= 72;
		slice = ddl / 4;
		patch = ddl % 4 + 2;
	}
	return true;
}

Int_t AliHLTTPCDefinitions::GetSingleSliceNr( ULong_t spec )
{
  // get the slice number provided that spec encodes a single slice
  // return -EINVAL if encoded min and max slice differ
  // return -ERANGE if slice number out of range
  AliHLTUInt8_t min=GetMinSliceNr(spec);
  AliHLTUInt8_t max=GetMaxSliceNr(spec);
  if (min!=max) return -EINVAL;
  if (max>=AliHLTTPCGeometry::GetNSlice()) return -ERANGE;
  return min;
}

Int_t AliHLTTPCDefinitions::GetSinglePatchNr( ULong_t spec )
{
  // get the patch number provided that spec encodes a single patch
  // return -EINVAL if encoded min and max patch differ
  // return -ERANGE if patch number out of range
  AliHLTUInt8_t min=GetMinPatchNr(spec);
  AliHLTUInt8_t max=GetMaxPatchNr(spec);
  if (min!=max) return -EINVAL;
  if (max>=AliHLTTPCGeometry::GetNumberOfPatches()) return -ERANGE;
  return min;
}
<|endoftext|>


<commit_before>#include <bits/stdc++.h>
#define sz(a) int((a).size())
#define pb push_back
#define all(c) (c).begin(),(c).end()
#define tr(c,i) for(typeof((c).begin() i = (c).begin(); i != (c).end(); i++)
#define present(c,x) ((c).find(x) != (c).end())
#define cpresent(c,x) (find(all(c),x) != (c).end())
#define REP(i,a,b) for(i=a;i<b;i++)
#define rep(i,n) REP(i,0,n)
#define ll long long
#define ull unsigned ll
#define MAX 1005
using namespace std;
int a[MAX],n,p;
int check(int time)
{
	int val=0;
	for(int i=0;i<n;i++)
	{
		val+=(-1+sqrt(1+(8*time)/a[i]))/2;
	}
	if(val>=p)
		return 1;
	return 0;
}
int main()
{
	int t;
	cin>>t;
	while(t--)
	{
		int i;
		cin>>p;
		cin>>n;
		int r=0;
		rep(i,n)
		{
			cin>>a[i];
			r=max(r,a[i]);
		}
		int hi=(r*p*(p+1))/2,lo=0,mid;
		while(lo<hi)
		{
			mid=(lo+hi)/2;
			if(check(mid))
				hi=mid;
			else
				lo=mid+1;
		}
		cout<<hi<<endl;
	}
	return 0;
}
<commit_msg>Change RT int-> bool<commit_after>#include <bits/stdc++.h>
#define sz(a) int((a).size())
#define pb push_back
#define all(c) (c).begin(),(c).end()
#define tr(c,i) for(typeof((c).begin() i = (c).begin(); i != (c).end(); i++)
#define present(c,x) ((c).find(x) != (c).end())
#define cpresent(c,x) (find(all(c),x) != (c).end())
#define REP(i,a,b) for(i=a;i<b;i++)
#define rep(i,n) REP(i,0,n)
#define ll long long
#define ull unsigned ll
#define MAX 1005
using namespace std;
int a[MAX],n,p;
bool check(int time)
{
	int val=0;
	for(int i=0;i<n;i++)
	{
		val+=(-1+sqrt(1+(8*time)/a[i]))/2;
	}
	if(val>=p)
		return true;
	return false;
}
int main()
{
	int t;
	cin>>t;
	while(t--)
	{
		int i;
		cin>>p;
		cin>>n;
		int r=0;
		rep(i,n)
		{
			cin>>a[i];
			r=max(r,a[i]);
		}
		int hi=(r*p*(p+1))/2,lo=0,mid;
		while(lo<hi)
		{
			mid=(lo+hi)/2;
			if(check(mid))
				hi=mid;
			else
				lo=mid+1;
		}
		cout<<hi<<endl;
	}
	return 0;
}
<|endoftext|>


<commit_before>// Copyright (c) 2021 The Orbit Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "DataViews/DataView.h"

#include <absl/strings/str_replace.h>

#include <cstddef>
#include <memory>

#include "ClientData/FunctionInfo.h"
#include "MetricsUploader/orbit_log_event.pb.h"
#include "OrbitBase/File.h"
#include "OrbitBase/Logging.h"

using orbit_client_data::FunctionInfo;
using orbit_client_data::ModuleData;
using orbit_client_data::ProcessData;

namespace orbit_data_views {

std::string FormatValueForCsv(std::string_view value) {
  std::string result;
  result.append("\"");
  result.append(absl::StrReplaceAll(value, {{"\"", "\"\""}}));
  result.append("\"");
  return result;
}

void DataView::Init() { InitSortingOrders(); }

void DataView::InitSortingOrders() {
  ORBIT_CHECK(sorting_orders_.empty());
  for (const auto& column : GetColumns()) {
    sorting_orders_.push_back(column.initial_order);
  }

  sorting_column_ = GetDefaultSortingColumn();
}

void DataView::OnSort(int column, std::optional<SortingOrder> new_order) {
  ORBIT_SCOPE_FUNCTION;

  if (!IsSortingAllowed()) {
    return;
  }

  ORBIT_CHECK(column >= 0);
  ORBIT_CHECK(static_cast<size_t>(column) < sorting_orders_.size());

  sorting_column_ = column;
  if (new_order.has_value()) {
    sorting_orders_[column] = new_order.value();
  }

  {
    ORBIT_SCOPE(absl::StrFormat("DoSort column[%i]", sorting_column_).c_str());
    DoSort();
  }
}

void DataView::OnFilter(const std::string& filter) {
  filter_ = filter;
  DoFilter();
  OnSort(sorting_column_, {});
}

void DataView::SetUiFilterString(const std::string& filter) {
  if (filter_callback_) {
    filter_callback_(filter);
  }
}

void DataView::OnDataChanged() {
  ORBIT_SCOPE_FUNCTION;
  DoFilter();
  OnSort(sorting_column_, std::optional<SortingOrder>{});
}

DataView::ActionStatus DataView::GetActionStatus(std::string_view action, int /* clicked_index */,
                                                 const std::vector<int>& /* selected_indices */) {
  if (action == kMenuActionCopySelection || action == kMenuActionExportToCsv) {
    return ActionStatus::kVisibleAndEnabled;
  }

  return ActionStatus::kInvisible;
}

std::vector<DataView::ActionGroup> DataView::GetContextMenuWithGrouping(
    int clicked_index, const std::vector<int>& selected_indices) {
  // GetContextmenuWithGrouping is called when OrbitTreeView::indexAt returns a valid index and
  // hence the selected_indices retrieved from OrbitTreeView::selectionModel()->selectedIndexes()
  // should not be empty.
  ORBIT_CHECK(!selected_indices.empty());

  std::vector<ActionGroup> menu;
  auto try_add_action_group = [&](std::vector<std::string_view> action_names) {
    ActionGroup action_group;
    for (std::string_view action_name : action_names) {
      switch (GetActionStatus(action_name, clicked_index, selected_indices)) {
        case ActionStatus::kVisibleAndEnabled:
          action_group.emplace_back(action_name, /*enabled=*/true);
          break;
        case ActionStatus::kVisibleButDisabled:
          action_group.emplace_back(action_name, /*enabled=*/false);
          break;
        case ActionStatus::kInvisible:
          break;
      }
    }
    if (!action_group.empty()) menu.push_back(std::move(action_group));
  };

  // Hooking related actions
  try_add_action_group({kMenuActionLoadSymbols, kMenuActionSelect, kMenuActionUnselect,
                        kMenuActionEnableFrameTrack, kMenuActionDisableFrameTrack,
                        kMenuActionVerifyFramePointers});

  try_add_action_group({kMenuActionDisassembly, kMenuActionSourceCode});

  // Navigating related actions
  try_add_action_group({kMenuActionAddIterator, kMenuActionJumpToFirst, kMenuActionJumpToLast,
                        kMenuActionJumpToMin, kMenuActionJumpToMax});

  // Preset related actions
  try_add_action_group({kMenuActionLoadPreset, kMenuActionDeletePreset, kMenuActionShowInExplorer});

  // Exporting relate actions
  try_add_action_group(
      {kMenuActionCopySelection, kMenuActionExportToCsv, kMenuActionExportEventsToCsv});
  return menu;
}

void DataView::OnContextMenu(const std::string& action, int /*menu_index*/,
                             const std::vector<int>& item_indices) {
  if (action == kMenuActionLoadSymbols) {
    OnLoadSymbolsRequested(item_indices);
  } else if (action == kMenuActionSelect) {
    OnSelectRequested(item_indices);
  } else if (action == kMenuActionUnselect) {
    OnUnselectRequested(item_indices);
  } else if (action == kMenuActionEnableFrameTrack) {
    OnEnableFrameTrackRequested(item_indices);
  } else if (action == kMenuActionDisableFrameTrack) {
    OnDisableFrameTrackRequested(item_indices);
  } else if (action == kMenuActionAddIterator) {
    OnIteratorRequested(item_indices);
  } else if (action == kMenuActionVerifyFramePointers) {
    OnVerifyFramePointersRequested(item_indices);

  } else if (action == kMenuActionDisassembly) {
    OnDisassemblyRequested(item_indices);
  } else if (action == kMenuActionSourceCode) {
    OnSourceCodeRequested(item_indices);

  } else if (action == kMenuActionJumpToFirst || action == kMenuActionJumpToLast ||
             action == kMenuActionJumpToMin || action == kMenuActionJumpToMax) {
    OnJumpToRequested(action, item_indices);

  } else if (action == kMenuActionLoadPreset) {
    OnLoadPresetRequested(item_indices);
  } else if (action == kMenuActionDeletePreset) {
    OnDeletePresetRequested(item_indices);
  } else if (action == kMenuActionShowInExplorer) {
    OnShowInExplorerRequested(item_indices);

  } else if (action == kMenuActionExportToCsv) {
    OnExportToCsvRequested();
  } else if (action == kMenuActionCopySelection) {
    OnCopySelectionRequested(item_indices);
  } else if (action == kMenuActionExportEventsToCsv) {
    OnExportEventsToCsvRequested(item_indices);
  }
}

std::vector<int> DataView::GetVisibleSelectedIndices() {
  std::vector<int> visible_selected_indices;
  for (size_t row = 0; row < indices_.size(); ++row) {
    if (selected_indices_.contains(indices_[row])) {
      visible_selected_indices.push_back(static_cast<int>(row));
    }
  }
  return visible_selected_indices;
}

void DataView::OnLoadSymbolsRequested(const std::vector<int>& selection) {
  std::vector<const ModuleData*> modules_to_load;
  for (int index : selection) {
    const ModuleData* module_data = GetModuleDataFromRow(index);
    if (module_data != nullptr && !module_data->is_loaded()) {
      modules_to_load.push_back(module_data);
    }
  }
  metrics_uploader_->SendLogEvent(
      orbit_metrics_uploader::OrbitLogEvent::ORBIT_LOAD_SYMBOLS_CLICKED);
  app_->RetrieveModulesAndLoadSymbols(modules_to_load);
}

void DataView::OnSelectRequested(const std::vector<int>& selection) {
  for (int i : selection) {
    const FunctionInfo* function = GetFunctionInfoFromRow(i);
    // Only hook functions for which we have symbols loaded.
    if (function != nullptr) {
      app_->SelectFunction(*function);
    }
  }
}

void DataView::OnUnselectRequested(const std::vector<int>& selection) {
  for (int i : selection) {
    const FunctionInfo* function = GetFunctionInfoFromRow(i);
    // If the frame belongs to a function for which no symbol is loaded 'function' is nullptr and
    // we can skip it since it can't be instrumented.
    if (function != nullptr) {
      app_->DeselectFunction(*function);
      // Unhooking a function implies disabling (and removing) the frame track for this function.
      // While it would be possible to keep the current frame track in the capture data, this would
      // lead to a somewhat inconsistent state where the frame track for this function is enabled
      // for the current capture but disabled for the next one.
      app_->DisableFrameTrack(*function);
      app_->RemoveFrameTrack(*function);
    }
  }
}

void DataView::OnEnableFrameTrackRequested(const std::vector<int>& selection) {
  metrics_uploader_->SendLogEvent(
      orbit_metrics_uploader::OrbitLogEvent::ORBIT_FRAME_TRACK_ENABLE_CLICKED);

  ORBIT_CHECK(app_->HasCaptureData());

  for (int i : selection) {
    const FunctionInfo* function = GetFunctionInfoFromRow(i);
    if (function == nullptr) continue;
    // Functions used as frame tracks must be hooked (selected), otherwise the
    // data to produce the frame track will not be captured.
    // The condition is supposed to prevent "selecting" a function when a capture
    // is loaded with no connection to a process being established.
    if (GetActionStatus(kMenuActionSelect, i, {i}) == ActionStatus::kVisibleAndEnabled) {
      app_->SelectFunction(*function);
    }

    app_->EnableFrameTrack(*function);
    app_->AddFrameTrack(*function);
  }
}

void DataView::OnDisableFrameTrackRequested(const std::vector<int>& selection) {
  metrics_uploader_->SendLogEvent(
      orbit_metrics_uploader::OrbitLogEvent::ORBIT_FRAME_TRACK_DISABLE_CLICKED);

  for (int i : selection) {
    const FunctionInfo* function = GetFunctionInfoFromRow(i);
    if (function == nullptr) continue;

    // When we remove a frame track, we do not unhook (deselect) the function as
    // it may have been selected manually (not as part of adding a frame track).
    // However, disable the frame track, so it is not recreated on the next capture.
    app_->DisableFrameTrack(*function);
    app_->RemoveFrameTrack(*function);
  }
}

void DataView::OnVerifyFramePointersRequested(const std::vector<int>& selection) {
  std::vector<const ModuleData*> modules_to_validate;
  modules_to_validate.reserve(selection.size());
  for (int i : selection) {
    const ModuleData* module = GetModuleDataFromRow(i);
    modules_to_validate.push_back(module);
  }

  if (!modules_to_validate.empty()) {
    app_->OnValidateFramePointers(modules_to_validate);
  }
}

void DataView::OnDisassemblyRequested(const std::vector<int>& selection) {
  const ProcessData* process_data = app_->GetTargetProcess();
  const uint32_t pid =
      process_data == nullptr ? app_->GetCaptureData().process_id() : process_data->pid();
  for (int i : selection) {
    const FunctionInfo* function = GetFunctionInfoFromRow(i);
    if (function != nullptr) app_->Disassemble(pid, *function);
  }
}

void DataView::OnSourceCodeRequested(const std::vector<int>& selection) {
  for (int i : selection) {
    const FunctionInfo* function = GetFunctionInfoFromRow(i);
    if (function != nullptr) app_->ShowSourceCode(*function);
  }
}

void DataView::OnExportToCsvRequested() {
  std::string save_file = app_->GetSaveFile(".csv");
  if (save_file.empty()) return;

  auto send_error = [&](const std::string& error_msg) {
    app_->SendErrorToUi(std::string{kMenuActionExportToCsv}, error_msg);
  };

  ErrorMessageOr<orbit_base::unique_fd> result = orbit_base::OpenFileForWriting(save_file);
  if (result.has_error()) {
    send_error(
        absl::StrFormat("Failed to open \"%s\" file: %s", save_file, result.error().message()));
    return;
  }

  const orbit_base::unique_fd& fd = result.value();

  constexpr const char* kFieldSeparator = ",";
  // CSV RFC requires lines to end with CRLF
  constexpr const char* kLineSeparator = "\r\n";

  size_t num_columns = GetColumns().size();
  {
    std::string header_line;
    for (size_t i = 0; i < num_columns; ++i) {
      header_line.append(FormatValueForCsv(GetColumns()[i].header));
      if (i < num_columns - 1) header_line.append(kFieldSeparator);
    }

    header_line.append(kLineSeparator);
    auto write_result = orbit_base::WriteFully(fd, header_line);
    if (write_result.has_error()) {
      send_error(absl::StrFormat("Error writing to \"%s\": %s", save_file,
                                 write_result.error().message()));
      return;
    }
  }

  size_t num_elements = GetNumElements();
  for (size_t i = 0; i < num_elements; ++i) {
    std::string line;
    for (size_t j = 0; j < num_columns; ++j) {
      line.append(FormatValueForCsv(GetValueForCopy(i, j)));
      if (j < num_columns - 1) line.append(kFieldSeparator);
    }
    line.append(kLineSeparator);
    auto write_result = orbit_base::WriteFully(fd, line);
    if (write_result.has_error()) {
      send_error(absl::StrFormat("Error writing to \"%s\": %s", save_file,
                                 write_result.error().message()));
      return;
    }
  }
}

void DataView::OnCopySelectionRequested(const std::vector<int>& selection) {
  constexpr const char* kFieldSeparator = "\t";
  constexpr const char* kLineSeparator = "\n";

  std::string clipboard;
  size_t num_columns = GetColumns().size();
  for (size_t i = 0; i < num_columns; ++i) {
    clipboard += GetColumns()[i].header;
    if (i < num_columns - 1) clipboard.append(kFieldSeparator);
  }
  clipboard.append(kLineSeparator);

  size_t num_elements = GetNumElements();
  for (size_t i : selection) {
    if (i >= num_elements) continue;
    for (size_t j = 0; j < num_columns; ++j) {
      clipboard += GetValueForCopy(i, j);
      if (j < num_columns - 1) clipboard.append(kFieldSeparator);
    }
    clipboard.append(kLineSeparator);
  }

  app_->SetClipboard(clipboard);
}

}  // namespace orbit_data_views
<commit_msg>Remove the wrongful ORBIT_CHECK (#3603)<commit_after>// Copyright (c) 2021 The Orbit Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "DataViews/DataView.h"

#include <absl/strings/str_replace.h>

#include <cstddef>
#include <memory>

#include "ClientData/FunctionInfo.h"
#include "MetricsUploader/orbit_log_event.pb.h"
#include "OrbitBase/File.h"
#include "OrbitBase/Logging.h"

using orbit_client_data::FunctionInfo;
using orbit_client_data::ModuleData;
using orbit_client_data::ProcessData;

namespace orbit_data_views {

std::string FormatValueForCsv(std::string_view value) {
  std::string result;
  result.append("\"");
  result.append(absl::StrReplaceAll(value, {{"\"", "\"\""}}));
  result.append("\"");
  return result;
}

void DataView::Init() { InitSortingOrders(); }

void DataView::InitSortingOrders() {
  ORBIT_CHECK(sorting_orders_.empty());
  for (const auto& column : GetColumns()) {
    sorting_orders_.push_back(column.initial_order);
  }

  sorting_column_ = GetDefaultSortingColumn();
}

void DataView::OnSort(int column, std::optional<SortingOrder> new_order) {
  ORBIT_SCOPE_FUNCTION;

  if (!IsSortingAllowed()) {
    return;
  }

  ORBIT_CHECK(column >= 0);
  ORBIT_CHECK(static_cast<size_t>(column) < sorting_orders_.size());

  sorting_column_ = column;
  if (new_order.has_value()) {
    sorting_orders_[column] = new_order.value();
  }

  {
    ORBIT_SCOPE(absl::StrFormat("DoSort column[%i]", sorting_column_).c_str());
    DoSort();
  }
}

void DataView::OnFilter(const std::string& filter) {
  filter_ = filter;
  DoFilter();
  OnSort(sorting_column_, {});
}

void DataView::SetUiFilterString(const std::string& filter) {
  if (filter_callback_) {
    filter_callback_(filter);
  }
}

void DataView::OnDataChanged() {
  ORBIT_SCOPE_FUNCTION;
  DoFilter();
  OnSort(sorting_column_, std::optional<SortingOrder>{});
}

DataView::ActionStatus DataView::GetActionStatus(std::string_view action, int /* clicked_index */,
                                                 const std::vector<int>& /* selected_indices */) {
  if (action == kMenuActionCopySelection || action == kMenuActionExportToCsv) {
    return ActionStatus::kVisibleAndEnabled;
  }

  return ActionStatus::kInvisible;
}

std::vector<DataView::ActionGroup> DataView::GetContextMenuWithGrouping(
    int clicked_index, const std::vector<int>& selected_indices) {
  // GetContextmenuWithGrouping is called when OrbitTreeView::indexAt returns a valid index and
  // hence the selected_indices retrieved from OrbitTreeView::selectionModel()->selectedIndexes()
  // should not be empty.
  ORBIT_CHECK(!selected_indices.empty());

  std::vector<ActionGroup> menu;
  auto try_add_action_group = [&](std::vector<std::string_view> action_names) {
    ActionGroup action_group;
    for (std::string_view action_name : action_names) {
      switch (GetActionStatus(action_name, clicked_index, selected_indices)) {
        case ActionStatus::kVisibleAndEnabled:
          action_group.emplace_back(action_name, /*enabled=*/true);
          break;
        case ActionStatus::kVisibleButDisabled:
          action_group.emplace_back(action_name, /*enabled=*/false);
          break;
        case ActionStatus::kInvisible:
          break;
      }
    }
    if (!action_group.empty()) menu.push_back(std::move(action_group));
  };

  // Hooking related actions
  try_add_action_group({kMenuActionLoadSymbols, kMenuActionSelect, kMenuActionUnselect,
                        kMenuActionEnableFrameTrack, kMenuActionDisableFrameTrack,
                        kMenuActionVerifyFramePointers});

  try_add_action_group({kMenuActionDisassembly, kMenuActionSourceCode});

  // Navigating related actions
  try_add_action_group({kMenuActionAddIterator, kMenuActionJumpToFirst, kMenuActionJumpToLast,
                        kMenuActionJumpToMin, kMenuActionJumpToMax});

  // Preset related actions
  try_add_action_group({kMenuActionLoadPreset, kMenuActionDeletePreset, kMenuActionShowInExplorer});

  // Exporting relate actions
  try_add_action_group(
      {kMenuActionCopySelection, kMenuActionExportToCsv, kMenuActionExportEventsToCsv});
  return menu;
}

void DataView::OnContextMenu(const std::string& action, int /*menu_index*/,
                             const std::vector<int>& item_indices) {
  if (action == kMenuActionLoadSymbols) {
    OnLoadSymbolsRequested(item_indices);
  } else if (action == kMenuActionSelect) {
    OnSelectRequested(item_indices);
  } else if (action == kMenuActionUnselect) {
    OnUnselectRequested(item_indices);
  } else if (action == kMenuActionEnableFrameTrack) {
    OnEnableFrameTrackRequested(item_indices);
  } else if (action == kMenuActionDisableFrameTrack) {
    OnDisableFrameTrackRequested(item_indices);
  } else if (action == kMenuActionAddIterator) {
    OnIteratorRequested(item_indices);
  } else if (action == kMenuActionVerifyFramePointers) {
    OnVerifyFramePointersRequested(item_indices);

  } else if (action == kMenuActionDisassembly) {
    OnDisassemblyRequested(item_indices);
  } else if (action == kMenuActionSourceCode) {
    OnSourceCodeRequested(item_indices);

  } else if (action == kMenuActionJumpToFirst || action == kMenuActionJumpToLast ||
             action == kMenuActionJumpToMin || action == kMenuActionJumpToMax) {
    OnJumpToRequested(action, item_indices);

  } else if (action == kMenuActionLoadPreset) {
    OnLoadPresetRequested(item_indices);
  } else if (action == kMenuActionDeletePreset) {
    OnDeletePresetRequested(item_indices);
  } else if (action == kMenuActionShowInExplorer) {
    OnShowInExplorerRequested(item_indices);

  } else if (action == kMenuActionExportToCsv) {
    OnExportToCsvRequested();
  } else if (action == kMenuActionCopySelection) {
    OnCopySelectionRequested(item_indices);
  } else if (action == kMenuActionExportEventsToCsv) {
    OnExportEventsToCsvRequested(item_indices);
  }
}

std::vector<int> DataView::GetVisibleSelectedIndices() {
  std::vector<int> visible_selected_indices;
  for (size_t row = 0; row < indices_.size(); ++row) {
    if (selected_indices_.contains(indices_[row])) {
      visible_selected_indices.push_back(static_cast<int>(row));
    }
  }
  return visible_selected_indices;
}

void DataView::OnLoadSymbolsRequested(const std::vector<int>& selection) {
  std::vector<const ModuleData*> modules_to_load;
  for (int index : selection) {
    const ModuleData* module_data = GetModuleDataFromRow(index);
    if (module_data != nullptr && !module_data->is_loaded()) {
      modules_to_load.push_back(module_data);
    }
  }
  metrics_uploader_->SendLogEvent(
      orbit_metrics_uploader::OrbitLogEvent::ORBIT_LOAD_SYMBOLS_CLICKED);
  app_->RetrieveModulesAndLoadSymbols(modules_to_load);
}

void DataView::OnSelectRequested(const std::vector<int>& selection) {
  for (int i : selection) {
    const FunctionInfo* function = GetFunctionInfoFromRow(i);
    // Only hook functions for which we have symbols loaded.
    if (function != nullptr) {
      app_->SelectFunction(*function);
    }
  }
}

void DataView::OnUnselectRequested(const std::vector<int>& selection) {
  for (int i : selection) {
    const FunctionInfo* function = GetFunctionInfoFromRow(i);
    // If the frame belongs to a function for which no symbol is loaded 'function' is nullptr and
    // we can skip it since it can't be instrumented.
    if (function != nullptr) {
      app_->DeselectFunction(*function);
      // Unhooking a function implies disabling (and removing) the frame track for this function.
      // While it would be possible to keep the current frame track in the capture data, this would
      // lead to a somewhat inconsistent state where the frame track for this function is enabled
      // for the current capture but disabled for the next one.
      app_->DisableFrameTrack(*function);
      app_->RemoveFrameTrack(*function);
    }
  }
}

void DataView::OnEnableFrameTrackRequested(const std::vector<int>& selection) {
  metrics_uploader_->SendLogEvent(
      orbit_metrics_uploader::OrbitLogEvent::ORBIT_FRAME_TRACK_ENABLE_CLICKED);

  for (int i : selection) {
    const FunctionInfo* function = GetFunctionInfoFromRow(i);
    if (function == nullptr) continue;
    // Functions used as frame tracks must be hooked (selected), otherwise the
    // data to produce the frame track will not be captured.
    // The condition is supposed to prevent "selecting" a function when a capture
    // is loaded with no connection to a process being established.
    if (GetActionStatus(kMenuActionSelect, i, {i}) == ActionStatus::kVisibleAndEnabled) {
      app_->SelectFunction(*function);
    }

    app_->EnableFrameTrack(*function);
    app_->AddFrameTrack(*function);
  }
}

void DataView::OnDisableFrameTrackRequested(const std::vector<int>& selection) {
  metrics_uploader_->SendLogEvent(
      orbit_metrics_uploader::OrbitLogEvent::ORBIT_FRAME_TRACK_DISABLE_CLICKED);

  for (int i : selection) {
    const FunctionInfo* function = GetFunctionInfoFromRow(i);
    if (function == nullptr) continue;

    // When we remove a frame track, we do not unhook (deselect) the function as
    // it may have been selected manually (not as part of adding a frame track).
    // However, disable the frame track, so it is not recreated on the next capture.
    app_->DisableFrameTrack(*function);
    app_->RemoveFrameTrack(*function);
  }
}

void DataView::OnVerifyFramePointersRequested(const std::vector<int>& selection) {
  std::vector<const ModuleData*> modules_to_validate;
  modules_to_validate.reserve(selection.size());
  for (int i : selection) {
    const ModuleData* module = GetModuleDataFromRow(i);
    modules_to_validate.push_back(module);
  }

  if (!modules_to_validate.empty()) {
    app_->OnValidateFramePointers(modules_to_validate);
  }
}

void DataView::OnDisassemblyRequested(const std::vector<int>& selection) {
  const ProcessData* process_data = app_->GetTargetProcess();
  const uint32_t pid =
      process_data == nullptr ? app_->GetCaptureData().process_id() : process_data->pid();
  for (int i : selection) {
    const FunctionInfo* function = GetFunctionInfoFromRow(i);
    if (function != nullptr) app_->Disassemble(pid, *function);
  }
}

void DataView::OnSourceCodeRequested(const std::vector<int>& selection) {
  for (int i : selection) {
    const FunctionInfo* function = GetFunctionInfoFromRow(i);
    if (function != nullptr) app_->ShowSourceCode(*function);
  }
}

void DataView::OnExportToCsvRequested() {
  std::string save_file = app_->GetSaveFile(".csv");
  if (save_file.empty()) return;

  auto send_error = [&](const std::string& error_msg) {
    app_->SendErrorToUi(std::string{kMenuActionExportToCsv}, error_msg);
  };

  ErrorMessageOr<orbit_base::unique_fd> result = orbit_base::OpenFileForWriting(save_file);
  if (result.has_error()) {
    send_error(
        absl::StrFormat("Failed to open \"%s\" file: %s", save_file, result.error().message()));
    return;
  }

  const orbit_base::unique_fd& fd = result.value();

  constexpr const char* kFieldSeparator = ",";
  // CSV RFC requires lines to end with CRLF
  constexpr const char* kLineSeparator = "\r\n";

  size_t num_columns = GetColumns().size();
  {
    std::string header_line;
    for (size_t i = 0; i < num_columns; ++i) {
      header_line.append(FormatValueForCsv(GetColumns()[i].header));
      if (i < num_columns - 1) header_line.append(kFieldSeparator);
    }

    header_line.append(kLineSeparator);
    auto write_result = orbit_base::WriteFully(fd, header_line);
    if (write_result.has_error()) {
      send_error(absl::StrFormat("Error writing to \"%s\": %s", save_file,
                                 write_result.error().message()));
      return;
    }
  }

  size_t num_elements = GetNumElements();
  for (size_t i = 0; i < num_elements; ++i) {
    std::string line;
    for (size_t j = 0; j < num_columns; ++j) {
      line.append(FormatValueForCsv(GetValueForCopy(i, j)));
      if (j < num_columns - 1) line.append(kFieldSeparator);
    }
    line.append(kLineSeparator);
    auto write_result = orbit_base::WriteFully(fd, line);
    if (write_result.has_error()) {
      send_error(absl::StrFormat("Error writing to \"%s\": %s", save_file,
                                 write_result.error().message()));
      return;
    }
  }
}

void DataView::OnCopySelectionRequested(const std::vector<int>& selection) {
  constexpr const char* kFieldSeparator = "\t";
  constexpr const char* kLineSeparator = "\n";

  std::string clipboard;
  size_t num_columns = GetColumns().size();
  for (size_t i = 0; i < num_columns; ++i) {
    clipboard += GetColumns()[i].header;
    if (i < num_columns - 1) clipboard.append(kFieldSeparator);
  }
  clipboard.append(kLineSeparator);

  size_t num_elements = GetNumElements();
  for (size_t i : selection) {
    if (i >= num_elements) continue;
    for (size_t j = 0; j < num_columns; ++j) {
      clipboard += GetValueForCopy(i, j);
      if (j < num_columns - 1) clipboard.append(kFieldSeparator);
    }
    clipboard.append(kLineSeparator);
  }

  app_->SetClipboard(clipboard);
}

}  // namespace orbit_data_views
<|endoftext|>


<commit_before>// Copyright (c) 2010 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "chrome/browser/service/service_process_control.h"

#include "base/command_line.h"
#include "base/file_path.h"
#include "base/process_util.h"
#include "base/thread.h"
#include "chrome/browser/browser_process.h"
#include "chrome/browser/browser_thread.h"
#include "chrome/browser/io_thread.h"
#include "chrome/browser/upgrade_detector.h"
#include "chrome/common/child_process_host.h"
#include "chrome/common/chrome_switches.h"
#include "chrome/common/notification_service.h"
#include "chrome/common/service_messages.h"
#include "chrome/common/service_process_util.h"

// ServiceProcessControl::Launcher implementation.
// This class is responsible for launching the service process on the
// PROCESS_LAUNCHER thread.
class ServiceProcessControl::Launcher
    : public base::RefCountedThreadSafe<ServiceProcessControl::Launcher> {
 public:
  Launcher(ServiceProcessControl* process, CommandLine* cmd_line)
      : process_(process),
        cmd_line_(cmd_line),
        launched_(false),
        retry_count_(0) {
  }

  // Execute the command line to start the process asynchronously.
  // After the comamnd is executed |task| is called with the process handle on
  // the UI thread.
  void Run(Task* task) {
    DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));

    BrowserThread::PostTask(BrowserThread::PROCESS_LAUNCHER, FROM_HERE,
                           NewRunnableMethod(this, &Launcher::DoRun, task));
  }

  bool launched() const { return launched_; }

 private:
  void DoRun(Task* task) {
    base::LaunchApp(*cmd_line_.get(), false, true, NULL);
    BrowserThread::PostTask(
        BrowserThread::IO, FROM_HERE,
        NewRunnableMethod(this, &Launcher::DoDetectLaunched, task));
  }

  void DoDetectLaunched(Task* task) {
    const uint32 kMaxLaunchDetectRetries = 10;

    launched_ = CheckServiceProcessReady();
    if (launched_ || (retry_count_ >= kMaxLaunchDetectRetries)) {
      BrowserThread::PostTask(BrowserThread::UI, FROM_HERE,
          NewRunnableMethod(this, &Launcher::Notify, task));
      return;
    }
    retry_count_++;
    // If the service process is not launched yet then check again in 2 seconds.
    const int kDetectLaunchRetry = 2000;
    MessageLoop::current()->PostDelayedTask(
        FROM_HERE,
        NewRunnableMethod(this, &Launcher::DoDetectLaunched, task),
        kDetectLaunchRetry);
  }

  void Notify(Task* task) {
    task->Run();
    delete task;
  }

  ServiceProcessControl* process_;
  scoped_ptr<CommandLine> cmd_line_;
  bool launched_;
  uint32 retry_count_;
};

// ServiceProcessControl implementation.
ServiceProcessControl::ServiceProcessControl(Profile* profile)
    : profile_(profile),
      message_handler_(NULL) {
}

ServiceProcessControl::~ServiceProcessControl() {
}

void ServiceProcessControl::ConnectInternal(Task* task) {
  // If the channel has already been established then we run the task
  // and return.
  if (channel_.get()) {
    if (task) {
      task->Run();
      delete task;
    }
    return;
  }

  // Actually going to connect.
  LOG(INFO) << "Connecting to Service Process IPC Server";
  connect_done_task_.reset(task);

  // Run the IPC channel on the shared IO thread.
  base::Thread* io_thread = g_browser_process->io_thread();

  // TODO(hclam): Handle error connecting to channel.
  const std::string channel_id = GetServiceProcessChannelName();
  channel_.reset(
      new IPC::SyncChannel(channel_id, IPC::Channel::MODE_CLIENT, this, NULL,
                           io_thread->message_loop(), true,
                           g_browser_process->shutdown_event()));
  channel_->set_sync_messages_with_no_timeout_allowed(false);

  // We just established a channel with the service process. Notify it if an
  // upgrade is available.
  if (Singleton<UpgradeDetector>::get()->notify_upgrade()) {
    Send(new ServiceMsg_UpdateAvailable);
  } else {
    if (registrar_.IsEmpty())
      registrar_.Add(this, NotificationType::UPGRADE_RECOMMENDED,
                     NotificationService::AllSources());
  }
}

void ServiceProcessControl::Launch(Task* task) {
  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));

  // If the service process is already running then connects to it.
  if (CheckServiceProcessReady()) {
    ConnectInternal(task);
    return;
  }

  // A service process should have a different mechanism for starting, but now
  // we start it as if it is a child process.
  FilePath exe_path = ChildProcessHost::GetChildPath(true);
  if (exe_path.empty()) {
    NOTREACHED() << "Unable to get service process binary name.";
  }

  CommandLine* cmd_line = new CommandLine(exe_path);
  cmd_line->AppendSwitchASCII(switches::kProcessType,
                              switches::kServiceProcess);

  const CommandLine& browser_command_line = *CommandLine::ForCurrentProcess();
  FilePath user_data_dir =
      browser_command_line.GetSwitchValuePath(switches::kUserDataDir);
  if (!user_data_dir.empty())
    cmd_line->AppendSwitchPath(switches::kUserDataDir, user_data_dir);

  std::string logging_level = browser_command_line.GetSwitchValueASCII(
      switches::kLoggingLevel);
  if (!logging_level.empty())
    cmd_line->AppendSwitchASCII(switches::kLoggingLevel, logging_level);

  if (browser_command_line.HasSwitch(switches::kWaitForDebuggerChildren)) {
    cmd_line->AppendSwitch(switches::kWaitForDebugger);
  }

  // And then start the process asynchronously.
  launcher_ = new Launcher(this, cmd_line);
  launcher_->Run(
      NewRunnableMethod(this, &ServiceProcessControl::OnProcessLaunched, task));
}

void ServiceProcessControl::OnProcessLaunched(Task* task) {
  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
  if (launcher_->launched()) {
    // After we have successfully created the service process we try to connect
    // to it. The launch task is transfered to a connect task.
    ConnectInternal(task);
  } else if (task) {
    // If we don't have process handle that means launching the service process
    // has failed.
    task->Run();
    delete task;
  }

  // We don't need the launcher anymore.
  launcher_ = NULL;
}

void ServiceProcessControl::OnMessageReceived(const IPC::Message& message) {
  IPC_BEGIN_MESSAGE_MAP(ServiceProcessControl, message)
      IPC_MESSAGE_HANDLER(ServiceHostMsg_GoodDay, OnGoodDay)
      IPC_MESSAGE_HANDLER(ServiceHostMsg_CloudPrintProxy_IsEnabled,
                          OnCloudPrintProxyIsEnabled)
  IPC_END_MESSAGE_MAP()
}

void ServiceProcessControl::OnChannelConnected(int32 peer_pid) {
  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
  if (!connect_done_task_.get())
    return;
  connect_done_task_->Run();
  connect_done_task_.reset();
}

void ServiceProcessControl::OnChannelError() {
  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
  channel_.reset();
  if (!connect_done_task_.get())
    return;
  connect_done_task_->Run();
  connect_done_task_.reset();
}

bool ServiceProcessControl::Send(IPC::Message* message) {
  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
  if (!channel_.get())
    return false;
  return channel_->Send(message);
}

// NotificationObserver implementation.
void ServiceProcessControl::Observe(NotificationType type,
                                    const NotificationSource& source,
                                    const NotificationDetails& details) {
  if (type == NotificationType::UPGRADE_RECOMMENDED) {
    Send(new ServiceMsg_UpdateAvailable);
  }
}

void ServiceProcessControl::OnGoodDay() {
  if (!message_handler_)
    return;

  message_handler_->OnGoodDay();
}

void ServiceProcessControl::OnCloudPrintProxyIsEnabled(bool enabled,
                                                       std::string email) {
  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
  if (cloud_print_status_callback_ != NULL) {
    cloud_print_status_callback_->Run(enabled, email);
    cloud_print_status_callback_.reset();
  }
}

bool ServiceProcessControl::SendHello() {
  return Send(new ServiceMsg_Hello());
}

bool ServiceProcessControl::Shutdown() {
  bool ret = Send(new ServiceMsg_Shutdown());
  channel_.reset();
  return ret;
}

bool ServiceProcessControl::EnableRemotingWithTokens(
    const std::string& user,
    const std::string& remoting_token,
    const std::string& talk_token) {
  return Send(
      new ServiceMsg_EnableRemotingWithTokens(user, remoting_token,
                                              talk_token));
}

bool ServiceProcessControl::GetCloudPrintProxyStatus(
    Callback2<bool, std::string>::Type* cloud_print_status_callback) {
  DCHECK(cloud_print_status_callback);
  cloud_print_status_callback_.reset(cloud_print_status_callback);
  return Send(new ServiceMsg_IsCloudPrintProxyEnabled);
}

DISABLE_RUNNABLE_METHOD_REFCOUNT(ServiceProcessControl);
<commit_msg>Fix crash on launch when remoting lab is turned on on Windows.<commit_after>// Copyright (c) 2010 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "chrome/browser/service/service_process_control.h"

#include "base/command_line.h"
#include "base/file_path.h"
#include "base/process_util.h"
#include "base/thread.h"
#include "chrome/browser/browser_process.h"
#include "chrome/browser/browser_thread.h"
#include "chrome/browser/io_thread.h"
#include "chrome/browser/upgrade_detector.h"
#include "chrome/common/child_process_host.h"
#include "chrome/common/chrome_switches.h"
#include "chrome/common/notification_service.h"
#include "chrome/common/service_messages.h"
#include "chrome/common/service_process_util.h"

// ServiceProcessControl::Launcher implementation.
// This class is responsible for launching the service process on the
// PROCESS_LAUNCHER thread.
class ServiceProcessControl::Launcher
    : public base::RefCountedThreadSafe<ServiceProcessControl::Launcher> {
 public:
  Launcher(ServiceProcessControl* process, CommandLine* cmd_line)
      : process_(process),
        cmd_line_(cmd_line),
        launched_(false),
        retry_count_(0) {
  }

  // Execute the command line to start the process asynchronously.
  // After the comamnd is executed |task| is called with the process handle on
  // the UI thread.
  void Run(Task* task) {
    DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));

    BrowserThread::PostTask(BrowserThread::PROCESS_LAUNCHER, FROM_HERE,
                           NewRunnableMethod(this, &Launcher::DoRun, task));
  }

  bool launched() const { return launched_; }

 private:
  void DoRun(Task* task) {
    base::LaunchApp(*cmd_line_.get(), false, true, NULL);
    BrowserThread::PostTask(
        BrowserThread::IO, FROM_HERE,
        NewRunnableMethod(this, &Launcher::DoDetectLaunched, task));
  }

  void DoDetectLaunched(Task* task) {
    const uint32 kMaxLaunchDetectRetries = 10;

    launched_ = CheckServiceProcessReady();
    if (launched_ || (retry_count_ >= kMaxLaunchDetectRetries)) {
      BrowserThread::PostTask(BrowserThread::UI, FROM_HERE,
          NewRunnableMethod(this, &Launcher::Notify, task));
      return;
    }
    retry_count_++;
    // If the service process is not launched yet then check again in 2 seconds.
    const int kDetectLaunchRetry = 2000;
    MessageLoop::current()->PostDelayedTask(
        FROM_HERE,
        NewRunnableMethod(this, &Launcher::DoDetectLaunched, task),
        kDetectLaunchRetry);
  }

  void Notify(Task* task) {
    task->Run();
    delete task;
  }

  ServiceProcessControl* process_;
  scoped_ptr<CommandLine> cmd_line_;
  bool launched_;
  uint32 retry_count_;
};

// ServiceProcessControl implementation.
ServiceProcessControl::ServiceProcessControl(Profile* profile)
    : profile_(profile),
      message_handler_(NULL) {
}

ServiceProcessControl::~ServiceProcessControl() {
}

void ServiceProcessControl::ConnectInternal(Task* task) {
  // If the channel has already been established then we run the task
  // and return.
  if (channel_.get()) {
    if (task) {
      task->Run();
      delete task;
    }
    return;
  }

  // Actually going to connect.
  LOG(INFO) << "Connecting to Service Process IPC Server";
  connect_done_task_.reset(task);

  // Run the IPC channel on the shared IO thread.
  base::Thread* io_thread = g_browser_process->io_thread();

  // TODO(hclam): Handle error connecting to channel.
  const std::string channel_id = GetServiceProcessChannelName();
  channel_.reset(
      new IPC::SyncChannel(channel_id, IPC::Channel::MODE_CLIENT, this, NULL,
                           io_thread->message_loop(), true,
                           g_browser_process->shutdown_event()));
  channel_->set_sync_messages_with_no_timeout_allowed(false);

  // We just established a channel with the service process. Notify it if an
  // upgrade is available.
  if (Singleton<UpgradeDetector>::get()->notify_upgrade()) {
    Send(new ServiceMsg_UpdateAvailable);
  } else {
    if (registrar_.IsEmpty())
      registrar_.Add(this, NotificationType::UPGRADE_RECOMMENDED,
                     NotificationService::AllSources());
  }
}

void ServiceProcessControl::Launch(Task* task) {
  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));

  // If the service process is already running then connects to it.
  if (CheckServiceProcessReady()) {
    ConnectInternal(task);
    return;
  }

  // Prevent quick calls to Launch in succession from causing a crash.
  // TODO(scottbyer) - ServiceProcessControl launch task callback code needs to
  // be enhanced to deal with this properly.  See
  // http://code.google.com/p/chromium/issues/detail?id=58802
  if (launcher_) {
    return;
  }

  // A service process should have a different mechanism for starting, but now
  // we start it as if it is a child process.
  FilePath exe_path = ChildProcessHost::GetChildPath(true);
  if (exe_path.empty()) {
    NOTREACHED() << "Unable to get service process binary name.";
  }

  CommandLine* cmd_line = new CommandLine(exe_path);
  cmd_line->AppendSwitchASCII(switches::kProcessType,
                              switches::kServiceProcess);

  const CommandLine& browser_command_line = *CommandLine::ForCurrentProcess();
  FilePath user_data_dir =
      browser_command_line.GetSwitchValuePath(switches::kUserDataDir);
  if (!user_data_dir.empty())
    cmd_line->AppendSwitchPath(switches::kUserDataDir, user_data_dir);

  std::string logging_level = browser_command_line.GetSwitchValueASCII(
      switches::kLoggingLevel);
  if (!logging_level.empty())
    cmd_line->AppendSwitchASCII(switches::kLoggingLevel, logging_level);

  if (browser_command_line.HasSwitch(switches::kWaitForDebuggerChildren)) {
    cmd_line->AppendSwitch(switches::kWaitForDebugger);
  }

  // And then start the process asynchronously.
  launcher_ = new Launcher(this, cmd_line);
  launcher_->Run(
      NewRunnableMethod(this, &ServiceProcessControl::OnProcessLaunched, task));
}

void ServiceProcessControl::OnProcessLaunched(Task* task) {
  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
  if (launcher_->launched()) {
    // After we have successfully created the service process we try to connect
    // to it. The launch task is transfered to a connect task.
    ConnectInternal(task);
  } else if (task) {
    // If we don't have process handle that means launching the service process
    // has failed.
    task->Run();
    delete task;
  }

  // We don't need the launcher anymore.
  launcher_ = NULL;
}

void ServiceProcessControl::OnMessageReceived(const IPC::Message& message) {
  IPC_BEGIN_MESSAGE_MAP(ServiceProcessControl, message)
      IPC_MESSAGE_HANDLER(ServiceHostMsg_GoodDay, OnGoodDay)
      IPC_MESSAGE_HANDLER(ServiceHostMsg_CloudPrintProxy_IsEnabled,
                          OnCloudPrintProxyIsEnabled)
  IPC_END_MESSAGE_MAP()
}

void ServiceProcessControl::OnChannelConnected(int32 peer_pid) {
  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
  if (!connect_done_task_.get())
    return;
  connect_done_task_->Run();
  connect_done_task_.reset();
}

void ServiceProcessControl::OnChannelError() {
  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
  channel_.reset();
  if (!connect_done_task_.get())
    return;
  connect_done_task_->Run();
  connect_done_task_.reset();
}

bool ServiceProcessControl::Send(IPC::Message* message) {
  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
  if (!channel_.get())
    return false;
  return channel_->Send(message);
}

// NotificationObserver implementation.
void ServiceProcessControl::Observe(NotificationType type,
                                    const NotificationSource& source,
                                    const NotificationDetails& details) {
  if (type == NotificationType::UPGRADE_RECOMMENDED) {
    Send(new ServiceMsg_UpdateAvailable);
  }
}

void ServiceProcessControl::OnGoodDay() {
  if (!message_handler_)
    return;

  message_handler_->OnGoodDay();
}

void ServiceProcessControl::OnCloudPrintProxyIsEnabled(bool enabled,
                                                       std::string email) {
  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
  if (cloud_print_status_callback_ != NULL) {
    cloud_print_status_callback_->Run(enabled, email);
    cloud_print_status_callback_.reset();
  }
}

bool ServiceProcessControl::SendHello() {
  return Send(new ServiceMsg_Hello());
}

bool ServiceProcessControl::Shutdown() {
  bool ret = Send(new ServiceMsg_Shutdown());
  channel_.reset();
  return ret;
}

bool ServiceProcessControl::EnableRemotingWithTokens(
    const std::string& user,
    const std::string& remoting_token,
    const std::string& talk_token) {
  return Send(
      new ServiceMsg_EnableRemotingWithTokens(user, remoting_token,
                                              talk_token));
}

bool ServiceProcessControl::GetCloudPrintProxyStatus(
    Callback2<bool, std::string>::Type* cloud_print_status_callback) {
  DCHECK(cloud_print_status_callback);
  cloud_print_status_callback_.reset(cloud_print_status_callback);
  return Send(new ServiceMsg_IsCloudPrintProxyEnabled);
}

DISABLE_RUNNABLE_METHOD_REFCOUNT(ServiceProcessControl);
<|endoftext|>


<commit_before>// arbitrary_precision_pi.cpp: generating a 'perfect' approximation of pi for a given number system
//
// Copyright (C) 2017-2020 Stillwater Supercomputing, Inc.
//
// This file is part of the universal numbers project, which is released under an MIT Open Source license.

// Configure the posit library with arithmetic exceptions
// enable posit arithmetic exceptions
#define POSIT_THROW_ARITHMETIC_EXCEPTION 1
#include <universal/posit/posit>

/*
Traditionally, we define the PI as the ratio of the circumference and its diameter.
Historically, however, was not always so.

It is known that this irrational number arose on the calculations of geometers
over time as a proportionality constant for at least 4 relationships, not necessarily in this order:

 - Between the circumference of a circle to its diameter;
 - Between the area of a circle and the square of its diameter;
 - Between the area of a sphere and the square of its diameter;
 - Between the volume of a sphere and the cube of its diameter;

The earliest known written references of the PI come from Babylon around 2000 BC.
Since then, their approximations have gone through several transformations until
they reach the billions of digits obtained today with the aid of the computer.

Historically, one of the best approximations of PI and interestingly also one of the oldest,
was used by the Chinese mathematician Zu Chongzhi (Sec.450 DC), which related the PI
as "something" between 3.1415926 and 3.1415927.

The calculation of PI has been revolutionized by the development of techniques of
infinite series, especially by mathematicians from europe in the 16th and 17th centuries.
An infinite series is the sum (or product) of the terms of an infinite sequence.
That approach was first discovered in India sometime between 1400 and 1500 AD.

Now let's look at the main discoveries in this area:

Viete's Series
The first infinite sequence discovered in Europe was an infinite product,
found by French mathematician Franois Vite in 1593:

2    sqrt(2)   sqrt(2 + sqrt(2))   sqrt(2 + sqrt(2 + sqrt(2)))
-  = ------- * ----------------- * --------------------------- * ...
pi      2             2                         2

Wallis's Series
The second infinite sequence, found in Europe by John Wallis in 1655, was also an infinite product:

pi   2   2   4   4   6   6   8   8
-- = - * - * - * - * - * - * - * - * ...
2    1   3   3   5   5   7   7   9

Leibniz's Series
Madhava of Sangamagrama, a Indian mathematician, formulated a series that was rediscovered
by scottish mathematician James Gregory in 1671, and by Leibniz in 1674:

	 4   4   4   4   4   4    4
pi = - - - + - - - + - - -- + -- ...
	 1   3   5   7   9   11   13

Nilakantha's Series
An infinite series for PI published by Nilakantha in the 15th century is:

		   4       4       4       4
pi = 3 + ----- - ----- + ----- - ------ + ...
		 2*3*4   4*5*6   6*7*8   8*9*10

*/

// best practice for C++ is to assign a literal
// but even this literal gets rounded in a double assignment
constexpr
double pi = 3.14159265358979323846;
//    pi  = 3.141592653589793115997963    value of above literal
//    ref = 3.14159265358979323846264338327950288419716939937510

// first 50 digits of pi
static std::string pi50 = "3.\
14159265358979323846264338327950288419716939937510";
// first 1000 digits of pi
static std::string pi1000 = "3.\
14159265358979323846264338327950288419716939937510\
58209749445923078164062862089986280348253421170679\
82148086513282306647093844609550582231725359408128\
48111745028410270193852110555964462294895493038196\
44288109756659334461284756482337867831652712019091\
45648566923460348610454326648213393607260249141273\
72458700660631558817488152092096282925409171536436\
78925903600113305305488204665213841469519415116094\
33057270365759591953092186117381932611793105118548\
07446237996274956735188575272489122793818301194912\
98336733624406566430860213949463952247371907021798\
60943702770539217176293176752384674818467669405132\
00056812714526356082778577134275778960917363717872\
14684409012249534301465495853710507922796892589235\
42019956112129021960864034418159813629774771309960\
51870721134999999837297804995105973173281609631859\
50244594553469083026425223082533446850352619311881\
71010003137838752886587533208381420617177669147303\
59825349042875546873115956286388235378759375195778\
18577805321712268066130019278766111959092164201989";

template<typename Real>
Real MethodOfViete(size_t N) {
	using namespace sw::unum;
	Real pi = Real(1);
	for (size_t i = N; i > 1; --i) {
		Real repeatingFactor = Real(2);
		for (size_t j = 1; j < i; ++j) {
			repeatingFactor = Real(2) + sqrt(repeatingFactor);
		}
		repeatingFactor = sqrt(repeatingFactor);
		pi = pi * repeatingFactor / Real(2);
	}
	pi *= sqrt(Real(2)) / Real(2);
	pi = Real(2) / pi;
	return pi;
}
 template<typename Real>
 Real MethodOfWallis(size_t N) {
	 using namespace sw::unum;
	 Real pi = Real(4);
	 for (size_t i = 3; i <= (N + 2); i += 2) {
		 pi = pi * ((i - 1) / Real(i)) * ((i + 1) / Real(i));
	 }
	 return pi;
 }

 template<typename Real>
 Real MethodOfMadhavaOfSangamagrama(size_t N) {
	 using namespace sw::unum;
	 Real pi = Real(0);
	 Real s = Real(1); // sign for the next iteration
	 for (size_t i = 1; i <= (2 * N); i += 2) {
		 pi = pi + s * (Real(4) / Real(i));
		 s = -s;
	 }
	 return pi;
 }

 template<typename Real>
 Real MethodOfNilakantha(size_t N) {
	 using namespace sw::unum;
	 Real pi = Real(3);
	 Real s = Real(1); // sign for the next iteration
	 for (size_t i = 2; i <= (2 * N); i += 2) {
		 pi = pi + s * (Real(4) / Real(i * (i + 1) * (i + 2)) );
		 s = -s;
	 }
	 return pi;
 }

int main(int argc, char** argv)
try {
	using namespace std;
	using namespace sw::unum;

	int nrOfFailedTestCases = 0;

	cout << "Perfect approximations of PI for different number systems" << endl;

	cout << pi1000 << endl;
	cout << "pi  = " << setprecision(25) << pi << endl;
	cout << "ref = " << pi50 << endl;

	using Real = double;
	size_t N = 100;
	cout << "Viete Series using " << N << " iteration" << endl; // doesn't really work for floats as rounding error accumulates to quickly
	cout << "pi  = " << setprecision(20) << MethodOfViete<float>(N) << endl;
	cout << "pi  = " << setprecision(20) << MethodOfViete<double>(N) << endl;
	cout << "ref = " << pi50 << endl;

	N = 1000000;
	cout << "Wallis Series using " << N << " iteration" << endl; // doesn't really work for floats as rounding error accumulates to quickly
	cout << "pi  = " << setprecision(20) << MethodOfWallis<float>(N) << endl;
	cout << "pi  = " << setprecision(20) << MethodOfWallis<double>(N) << endl;
	cout << "ref = " << pi50 << endl;

	N = 10000000;
	cout << "Madhava of Sangamagrama (or Leibniz) Series using " << N << " iteration" << endl; // doesn't really work for floats as rounding error accumulates to quickly
	cout << "pi  = " << setprecision(20) << MethodOfMadhavaOfSangamagrama<float>(N) << endl;
	cout << "pi  = " << setprecision(20) << MethodOfMadhavaOfSangamagrama<double>(N) << endl;
	cout << "ref = " << pi50 << endl;

	N = 10000;
	cout << "Nilakantha Series using " << N << " iteration" << endl; // doesn't really work for floats as rounding error accumulates to quickly
	cout << "pi  = " << setprecision(20) << MethodOfNilakantha<float>(N) << endl;
	cout << "pi  = " << setprecision(20) << MethodOfNilakantha<double>(N) << endl;
	cout << "ref = " << pi50 << endl;

	// 1000 digits -> 1.e1000 -> 2^3322 -> 1.051103774764883380737596422798e+1000 -> you will need 3322 bits to represent 1000 digits of pi

	return (nrOfFailedTestCases > 0 ? EXIT_FAILURE : EXIT_SUCCESS);
}
catch (char const* msg) {
	std::cerr << msg << std::endl;
	return EXIT_FAILURE;
}
catch (const posit_arithmetic_exception& err) {
	std::cerr << "Uncaught posit arithmetic exception: " << err.what() << std::endl;
	return EXIT_FAILURE;
}
catch (const quire_exception& err) {
	std::cerr << "Uncaught quire exception: " << err.what() << std::endl;
	return EXIT_FAILURE;
}
catch (const posit_internal_exception& err) {
	std::cerr << "Uncaught posit internal exception: " << err.what() << std::endl;
	return EXIT_FAILURE;
}
catch (const std::runtime_error& err) {
	std::cerr << "Uncaught runtime exception: " << err.what() << std::endl;
	return EXIT_FAILURE;
}
catch (...) {
	std::cerr << "Caught unknown exception" << std::endl;
	return EXIT_FAILURE;
}
<commit_msg>adding explanation to pi test<commit_after>// arbitrary_precision_pi.cpp: generating a 'perfect' approximation of pi for a given number system
//
// Copyright (C) 2017-2020 Stillwater Supercomputing, Inc.
//
// This file is part of the universal numbers project, which is released under an MIT Open Source license.

// Configure the posit library with arithmetic exceptions
// enable posit arithmetic exceptions
#define POSIT_THROW_ARITHMETIC_EXCEPTION 1
#include <universal/posit/posit>

/*
Traditionally, we define the PI as the ratio of the circumference and its diameter.
Historically, however, was not always so.

It is known that this irrational number arose on the calculations of geometers
over time as a proportionality constant for at least 4 relationships, not necessarily in this order:

 - Between the circumference of a circle to its diameter;
 - Between the area of a circle and the square of its diameter;
 - Between the area of a sphere and the square of its diameter;
 - Between the volume of a sphere and the cube of its diameter;

The earliest known written references of the PI come from Babylon around 2000 BC.
Since then, their approximations have gone through several transformations until
they reach the billions of digits obtained today with the aid of the computer.

Historically, one of the best approximations of PI and interestingly also one of the oldest,
was used by the Chinese mathematician Zu Chongzhi (Sec.450 DC), which related the PI
as "something" between 3.1415926 and 3.1415927.

The calculation of PI has been revolutionized by the development of techniques of
infinite series, especially by mathematicians from europe in the 16th and 17th centuries.
An infinite series is the sum (or product) of the terms of an infinite sequence.
That approach was first discovered in India sometime between 1400 and 1500 AD.

Now let's look at the main discoveries in this area:

Viete's Series
The first infinite sequence discovered in Europe was an infinite product,
found by French mathematician Franois Vite in 1593:

2    sqrt(2)   sqrt(2 + sqrt(2))   sqrt(2 + sqrt(2 + sqrt(2)))
-  = ------- * ----------------- * --------------------------- * ...
pi      2             2                         2

Wallis's Series
The second infinite sequence, found in Europe by John Wallis in 1655, was also an infinite product:

pi   2   2   4   4   6   6   8   8
-- = - * - * - * - * - * - * - * - * ...
2    1   3   3   5   5   7   7   9

Leibniz's Series
Madhava of Sangamagrama, a Indian mathematician, formulated a series that was rediscovered
by scottish mathematician James Gregory in 1671, and by Leibniz in 1674:

	 4   4   4   4   4   4    4
pi = - - - + - - - + - - -- + -- ...
	 1   3   5   7   9   11   13

Nilakantha's Series
An infinite series for PI published by Nilakantha in the 15th century is:

		   4       4       4       4
pi = 3 + ----- - ----- + ----- - ------ + ...
		 2*3*4   4*5*6   6*7*8   8*9*10

*/

// best practice for C++ is to assign a literal
// but even this literal gets rounded in a double assignment
constexpr
double pi = 3.14159265358979323846;
//    pi  = 3.141592653589793115997963    value of above literal
//    ref = 3.14159265358979323846264338327950288419716939937510

// first 50 digits of pi
static std::string pi50 = "3.\
14159265358979323846264338327950288419716939937510";
// first 1000 digits of pi
static std::string pi1000 = "3.\
14159265358979323846264338327950288419716939937510\
58209749445923078164062862089986280348253421170679\
82148086513282306647093844609550582231725359408128\
48111745028410270193852110555964462294895493038196\
44288109756659334461284756482337867831652712019091\
45648566923460348610454326648213393607260249141273\
72458700660631558817488152092096282925409171536436\
78925903600113305305488204665213841469519415116094\
33057270365759591953092186117381932611793105118548\
07446237996274956735188575272489122793818301194912\
98336733624406566430860213949463952247371907021798\
60943702770539217176293176752384674818467669405132\
00056812714526356082778577134275778960917363717872\
14684409012249534301465495853710507922796892589235\
42019956112129021960864034418159813629774771309960\
51870721134999999837297804995105973173281609631859\
50244594553469083026425223082533446850352619311881\
71010003137838752886587533208381420617177669147303\
59825349042875546873115956286388235378759375195778\
18577805321712268066130019278766111959092164201989";

template<typename Real>
Real MethodOfViete(size_t N) {
	using namespace sw::unum;
	Real pi = Real(1);
	for (size_t i = N; i > 1; --i) {
		Real repeatingFactor = Real(2);
		for (size_t j = 1; j < i; ++j) {
			repeatingFactor = Real(2) + sqrt(repeatingFactor);
		}
		repeatingFactor = sqrt(repeatingFactor);
		pi = pi * repeatingFactor / Real(2);
	}
	pi *= sqrt(Real(2)) / Real(2);
	pi = Real(2) / pi;
	return pi;
}
 template<typename Real>
 Real MethodOfWallis(size_t N) {
	 using namespace sw::unum;
	 Real pi = Real(4);
	 for (size_t i = 3; i <= (N + 2); i += 2) {
		 pi = pi * (Real(i - 1) / Real(i)) * (Real(i + 1) / Real(i));
	 }
	 return pi;
 }

 template<typename Real>
 Real MethodOfMadhavaOfSangamagrama(size_t N) {
	 using namespace sw::unum;
	 Real pi = Real(0);
	 Real s = Real(1); // sign for the next iteration
	 for (size_t i = 1; i <= (2 * N); i += 2) {
		 pi = pi + s * (Real(4) / Real(i));
		 s = -s;
	 }
	 return pi;
 }

 template<typename Real>
 Real MethodOfNilakantha(size_t N) {
	 using namespace sw::unum;
	 Real pi = Real(3);
	 Real s = Real(1); // sign for the next iteration
	 for (size_t i = 2; i <= (2 * N); i += 2) {
		 pi = pi + s * (Real(4) / Real(i * (i + 1) * (i + 2)) );
		 s = -s;
	 }
	 return pi;
 }

int main(int argc, char** argv)
try {
	using namespace std;
	using namespace sw::unum;

	int nrOfFailedTestCases = 0;

	cout << "Perfect approximations of PI for different number systems" << endl;

	cout << pi1000 << endl;
	cout << "pi  = " << setprecision(25) << pi << endl;
	cout << "ref = " << pi50 << endl;

	using Real = posit<64,3>;
	size_t N = 100;
	cout << "Viete Series using " << N << " iteration" << endl; // doesn't really work for floats as rounding error accumulates to quickly
	cout << "pi  = " << setprecision(20) << MethodOfViete<float>(N) << endl;
	cout << "pi  = " << setprecision(20) << MethodOfViete<double>(N) << endl;
	cout << "ref = " << pi50 << endl;
	cout << "pi  = " << setprecision(20) << MethodOfViete<Real>(N) << endl;

	N = 1000;
	cout << "Wallis Series using " << N << " iteration" << endl; // doesn't really work for floats as rounding error accumulates to quickly
	cout << "pi  = " << setprecision(20) << MethodOfWallis<float>(N) << endl;
	cout << "pi  = " << setprecision(20) << MethodOfWallis<double>(N) << endl;
	cout << "ref = " << pi50 << endl;
	cout << "pi  = " << setprecision(20) << MethodOfWallis<Real>(N) << endl;

	N = 1000;
	cout << "Madhava of Sangamagrama (or Leibniz) Series using " << N << " iteration" << endl; // doesn't really work for floats as rounding error accumulates to quickly
	cout << "pi  = " << setprecision(20) << MethodOfMadhavaOfSangamagrama<float>(N) << endl;
	cout << "pi  = " << setprecision(20) << MethodOfMadhavaOfSangamagrama<double>(N) << endl;
	cout << "ref = " << pi50 << endl;
	cout << "pi  = " << setprecision(20) << MethodOfMadhavaOfSangamagrama<Real>(N) << endl;

	N = 1000;
	cout << "Nilakantha Series using " << N << " iteration" << endl; // doesn't really work for floats as rounding error accumulates to quickly
	cout << "pi  = " << setprecision(20) << MethodOfNilakantha<float>(N) << endl;
	cout << "pi  = " << setprecision(20) << MethodOfNilakantha<double>(N) << endl;
	cout << "ref = " << pi50 << endl;
	cout << "pi  = " << setprecision(20) << MethodOfNilakantha<Real>(N) << endl;

	// 1000 digits -> 1.e1000 -> 2^3322 -> 1.051103774764883380737596422798e+1000 -> you will need 3322 bits to represent 1000 digits of pi

	return (nrOfFailedTestCases > 0 ? EXIT_FAILURE : EXIT_SUCCESS);
}
catch (char const* msg) {
	std::cerr << msg << std::endl;
	return EXIT_FAILURE;
}
catch (const posit_arithmetic_exception& err) {
	std::cerr << "Uncaught posit arithmetic exception: " << err.what() << std::endl;
	return EXIT_FAILURE;
}
catch (const quire_exception& err) {
	std::cerr << "Uncaught quire exception: " << err.what() << std::endl;
	return EXIT_FAILURE;
}
catch (const posit_internal_exception& err) {
	std::cerr << "Uncaught posit internal exception: " << err.what() << std::endl;
	return EXIT_FAILURE;
}
catch (const std::runtime_error& err) {
	std::cerr << "Uncaught runtime exception: " << err.what() << std::endl;
	return EXIT_FAILURE;
}
catch (...) {
	std::cerr << "Caught unknown exception" << std::endl;
	return EXIT_FAILURE;
}
<|endoftext|>