<commit_before>class AliAnalysisGrid;
const char *dataset   = "";
TString anaLibs = "";
//Int_t iESDfilter       = 1;
Int_t iESDfilter       = 0;
Int_t iAODTagCreation  = 1;
Int_t iAODAddMCBranch  = 0;

//______________________________________________________________________________
void run(
         const char* runtype = "local", // local, proof or grid
         const char *gridmode = "test", // Set the run mode (can be "full", "test", "offline", "submit" or "terminate"). Full & Test work for proof
         const bool bMCtruth = 1, // 1 = MCEvent handler is on (MC truth), 0 = MCEvent handler is off (MC reconstructed/real data)
         const bool bMCphyssel = 1, // 1 = looking at MC truth or reconstructed, 0 = looking at real data
         const Long64_t nentries = 2000, // for local and proof mode, ignored in grid mode. Set to 1234567890 for all events.
         const Long64_t firstentry = 0, // for local and proof mode, ignored in grid mode
         const char *proofdataset = "/alice/data/LHC10c_000120821_p1", // path to dataset on proof cluster, for proof analysis
         const char *proofcluster = "alice-caf.cern.ch", // which proof cluster to use in proof mode
         const char *taskname = "Flowd_PbPb2011"
         )
{
  // check run type
  if(runtype != "local" && runtype != "proof" && runtype != "grid"){
    Printf("\n\tIncorrect run option, check first argument of run macro");
    Printf("\tint runtype = local, proof or grid\n");
    return;
  }
  Printf("%s analysis chosen",runtype);

  gROOT->ProcessLine(".include $ALICE_ROOT/include");

  gSystem->AddIncludePath("-I$ALICE_ROOT/include");
  gSystem->AddIncludePath("-I$ALICE_ROOT/PWGHF/vertexingHF");
  // Load analysis specific libraries
  //=====================================================================

  gSystem->SetIncludePath("-I. -I$ROOTSYS/include -I$ALICE_ROOT -I$ALICE_ROOT/include -I$ALICE_ROOT/ITS -I$ALICE_ROOT/TPC -I$ALICE_ROOT/CONTAINERS -I$ALICE_ROOT/STEER/STEER -I$ALICE_ROOT/STEER/STEERBase -I$ALICE_ROOT/STEER/ESD -I$ALICE_ROOT/STEER/AOD -I$ALICE_ROOT/TRD -I$ALICE_ROOT/macros -I$ALICE_ROOT/ANALYSIS  -I$ALICE_ROOT/OADB -I$ALICE_ROOT/PWGHF -I$ALICE_ROOT/PWGHF/base -I$ALICE_ROOT/PWGHF/vertexingHF -I$ALICE_ROOT/PWG/FLOW/Base -I$ALICE_ROOT/PWG/FLOW/Tasks -g");

  gSystem->Load("libTree.so");
  gSystem->Load("libGeom.so");
  gSystem->Load("libPhysics.so");
  gSystem->Load("libVMC.so");
  gSystem->Load("libMinuit.so");
  gSystem->Load("libSTEERBase.so");
  gSystem->Load("libESD.so");
  gSystem->Load("libAOD.so");
  gSystem->Load("libANALYSIS.so");
  gSystem->Load("libOADB.so");
  gSystem->Load("libANALYSISalice.so");
  gSystem->Load("libCORRFW.so");
  gSystem->Load("libPWGHFbase.so");
  gSystem->Load("libPWGflowBase.so");
  gSystem->Load("libPWGflowTasks.so");
  gSystem->Load("libPWGHFvertexingHF.so");

  // Load analysis specific libraries
  //=====================================================================
  //------ Create AlienPlugin ---------------------
  AliAnalysisGrid *plugin = 0x0;
  TChain *chain = 0x0;
  if (runtype != "local") {
    plugin = CreateAlienHandler(taskname, gridmode, proofcluster, proofdataset);
    if(!plugin) return;
  } else {
    gROOT->LoadMacro("$ALICE_ROOT/PWGCF/Correlations/macros/dphicorrelations/CreateESDChain.C");
    chain = CreateESDChain("ESDs.txt");
  }

  //---- Create the analysis manager
  AliAnalysisManager* mgr = new AliAnalysisManager(taskname);
  if(plugin) mgr->SetGridHandler(plugin);

  //  Input

  AliESDInputHandler* iH = new AliESDInputHandler("handler","handler for my analisys");
  mgr->SetInputEventHandler(iH);

  //--------------------------------------------------------------
  // Other tasks

  // Physics selection
  gROOT->LoadMacro("$ALICE_ROOT/ANALYSIS/macros/AddTaskPhysicsSelection.C");
  AliPhysicsSelectionTask *physSel = AddTaskPhysicsSelection(useMC);
  // Centrality selection
  gROOT->LoadMacro("$ALICE_ROOT/ANALYSIS/macros/AddTaskCentrality.C");
  AliCentralitySelectionTask *taskCentr = AddTaskCentrality();

  gROOT->LoadMacro("$ALICE_ROOT/ANALYSIS/macros/AddTaskPIDResponse.C");
  AliAnalysisTaskPIDResponse *pidTask = AddTaskPIDResponse(useMC);

  gROOT->LoadMacro("./AliAnalysisTaskFlowd.cxx+g");//$ALICE_ROOT/PWGLF/STRANGENESS/Cascades/AliAnalysisTaskCheckCascadePbPb.cxx++g");
  gROOT->LoadMacro("./AddTaskFlowd.C");//$ALICE_ROOT/PWGLF/STRANGENESS/Cascades/macros/AddTaskCheckCascadePbPb.C");
  AliAnalysisTaskFlowd *task = AddTaskFlowd(kTRUE);

  //__________________________________________________________________________
  // Disable debug printouts
  mgr->SetDebugLevel(3);
  AliLog::SetGlobalLogLevel(AliLog::kFatal);
  AliLog::SetGlobalDebugLevel(0);

  //__________________________________________________________________________
  if (!mgr->InitAnalysis()) return;
  mgr->PrintStatus();
  // Start analysis in grid.
  if (runtype == "local")
    mgr->StartAnalysis(runtype,chain,nentries,firstentry);
  else
    mgr->StartAnalysis(runtype,nentries,firstentry);
};

}

//______________________________________________________________________________
AliAnalysisGrid* CreateAlienHandler(const char *taskname, const char *gridmode, const char *proofcluster, const char *proofdataset)
{
  AliAnalysisAlien *plugin = new AliAnalysisAlien();
  // Set the run mode (can be "full", "test", "offline", "submit" or "terminate")
  plugin->SetRunMode(gridmode);

  // Set versions of used packages

  plugin->SetAPIVersion("V1.1x");
  plugin->SetROOTVersion("v5-34-08");
  plugin->SetAliROOTVersion("vAN-20140915");
  plugin->SetExecutableCommand("aliroot -b -q");

  // Declare input data to be processed.

  // Method 1: Create automatically XML collections using alien 'find' command.
  // Define production directory LFN
  //    plugin->SetGridDataDir("/alice/data/2010/LHC10h");

  // plugin->SetGridDataDir(" /alice/data/2011/LHC11h_2/"); //sim
  // plugin->SetDataPattern("pass2/*AliAOD.root"); // sim

  plugin->SetGridDataDir("/alice/data/2011/LHC11h_2/"); //sim
  plugin->SetDataPattern("/pass2/ESDs/*AliESD.root"); // sim
  plugin->SetRunPrefix("000");   // real data

  Int_t runlist[1]={167693};
  for(Int_t i=0;i<1;i++)
    plugin->AddRunNumber(runlist[i]);

  //    plugin->AddRunNumber(139505);
  //  plugin->AddRunNumber(138652);
  plugin->SetNrunsPerMaster(1);
  plugin->SetOutputToRunNo();

  // Method 2: Declare existing data files (raw collections, xml collections, root file)
  //   plugin->AddDataFile("/alice/data/2008/LHC08c/000057657/raw/Run57657.Merged.RAW.tag.root");

  // Define alien work directory where all files will be copied. Relative to alien $HOME.
  plugin->SetGridWorkingDir(taskname);

  // Declare alien output directory. Relative to working directory.
  plugin->SetGridOutputDir("output"); // In this case will be $HOME/taskname/out

  //  plugin->SetAdditionalLibs("libTree.so libGeom.so libPhysics.so libVMC.so libMinuit.so libSTEERBase.so libESD.so libAOD.so  libANALYSIS.so libOADB.so libANALYSISalice.so libCORRFW.so libPWGHFbase.so libPWGflowBase.so libPWGflowTasks.so libPWGHFvertexingHF.so");

  // plugin->SetAdditionalLibs("libCORRFW.so libPWGHFbase.so libPWGflowBase.so libPWGflowTasks.so libPWGHFvertexingHF.so");

  plugin->SetAnalysisSource("AliAnalysisTaskFlowd.cxx");

  cout<<"-->>>>>>>>>>>>>>>>>>>>>>>>> 1"<<endl;

  // Declare the analysis source files names separated by blancs. To be compiled runtime
  // using ACLiC on the worker nodes.
  //plugin->SetAdditionalLibs("libPWGHFbase.so libPWGflowBase.so libPWGflowTasks.so libPWGHFvertexingHF.so AliAODMuonReplicator0.so");

  cout<<"-->>>>>>>>>>>>>>>>>>>>>>>>> 2"<<endl;
  // plugin->SetAdditionalLibs("libTree.so libGeom.so libPhysics.so libVMC.so libMinuit.so libSTEERBase.so libESD.so libAOD.so libANALYSIS.so libOADB.so libANALYSISalice.so libCORRFW.so libPWGHFbase.so libPWGflowBase.so libPWGflowTasks.so libPWGHFvertexingHF.so");

  // plugin->SetAnalysisSource("AliAnalysisTaskESDMuonFilterO.cxx");
  //plugin->SetAnalysisSource("AliAODMuonReplicator0.cxx");

  // Declare all libraries (other than the default ones for the framework. These will be
  // loaded by the generated analysis macro. Add all extra files (task .cxx/.h) here.
  // plugin->SetAdditionalLibs("AliAODMuonReplicator0_cxx.so");
  // plugin->SetAdditionalLibs("AliAnalysisTaskESDMuonFilterO_cxx.so");

  //questo
  plugin->SetAdditionalLibs("libPWGflowBase.so libPWGflowTasks.so libPWGHFbase.so libPWGHFvertexingHF.so");
  plugin->AddIncludePath("-I. -I$ROOTSYS/include -I$ALICE_ROOT -I$ALICE_ROOT/include -I$ALICE_ROOT/ITS -I$ALICE_ROOT/TPC -I$ALICE_ROOT/CONTAINERS -I$ALICE_ROOT/STEER/STEER -I$ALICE_ROOT/STEER/STEERBase -I$ALICE_ROOT/STEER/ESD -I$ALICE_ROOT/STEER/AOD -I$ALICE_ROOT/TRD -I$ALICE_ROOT/macros -I$ALICE_ROOT/ANALYSIS  -I$ALICE_ROOT/OADB -I$ALICE_ROOT/PWGHF -I$ALICE_ROOT/PWGHF/base -I$ALICE_ROOT/PWGHF/vertexingHF -I$ALICE_ROOT/PWG/FLOW/Base -I$ALICE_ROOT/PWG/FLOW/Tasks -g");

  // plugin->SetAdditionalLibs("AliAODMuonReplicator0.h AliAODMuonReplicator0.cxx");
  // plugin->SetAdditionalLibs("AliAnalysisTaskESDMuonFilterO.h AliAnalysisTaskESDMuonFilterO.cxx");

  //plugin->SetAdditionalLibs("AliAODMuonReplicator0.h AliAODMuonReplicator0.cxx AliAnalysisTaskESDMuonFilterO.h AliAnalysisTaskESDMuonFilterO.cxx");

  cout<<"-->>>>>>>>>>>>>>>>>>>>>>>>> 3"<<endl;

  // plugin->SetAdditionalLibs("AliAODMuonReplicator0.h AliAODMuonReplicator0.cxx");

  // plugin->SetAdditionalLibs("AliAnalysisTaskESDMuonFilterO.h AliAnalysisTaskESDMuonFilterO.cxx");

  // Declare the output file names separated by blancs.
  // (can be like: file.root or file.root@ALICE::Niham::File)
  // To only save certain files, use SetDefaultOutputs(kFALSE), and then
  // SetOutputFiles("list.root other.filename") to choose which files to save
  plugin->SetDefaultOutputs();
  //plugin->SetOutputFiles("list.root");

  // Optionally set a name for the generated analysis macro (default MyAnalysis.C)
  plugin->SetAnalysisMacro(Form("%s.C",taskname));

  // Optionally set maximum number of input files/subjob (default 100, put 0 to ignore)
  plugin->SetSplitMaxInputFileNumber(100);

  // Optionally modify the executable name (default analysis.sh)
  plugin->SetExecutable(Form("%s.sh",taskname));

  // set number of test files to use in "test" mode
  plugin->SetNtestFiles(10);

  // Optionally resubmit threshold.
  plugin->SetMasterResubmitThreshold(90);

  // Optionally set time to live (default 30000 sec)
  plugin->SetTTL(30000);

  // Optionally set input format (default xml-single)
  plugin->SetInputFormat("xml-single");

  // Optionally modify the name of the generated JDL (default analysis.jdl)
  plugin->SetJDLName(Form("%s.jdl",taskname));

  // Optionally modify job price (default 1)
  plugin->SetPrice(1);

  // Optionally modify split mode (default 'se')
  plugin->SetSplitMode("se");

  //----------------------------------------------------------
  //---      PROOF MODE SPECIFIC SETTINGS         ------------
  //----------------------------------------------------------
  // Proof cluster
  plugin->SetProofCluster(proofcluster);
  // Dataset to be used
  plugin->SetProofDataSet(proofdataset);
  // May need to reset proof. Supported modes: 0-no reset, 1-soft, 2-hard
  plugin->SetProofReset(0);
  // May limit number of workers
  plugin->SetNproofWorkers(0);
  // May limit the number of workers per slave
  plugin->SetNproofWorkersPerSlave(1);
  // May use a specific version of root installed in proof
  plugin->SetRootVersionForProof("current");
  // May set the aliroot mode. Check http://aaf.cern.ch/node/83
  plugin->SetAliRootMode("default"); // Loads AF libs by default
  // May request ClearPackages (individual ClearPackage not supported)
  plugin->SetClearPackages(kFALSE);
  // Plugin test mode works only providing a file containing test file locations, used in "local" mode also
  plugin->SetFileForTestMode("files.txt"); // file should contain path name to a local directory containg *ESDs.root etc
  // Request connection to alien upon connection to grid
  plugin->SetProofConnectGrid(kFALSE);

  cout<<"-->>>>>>>>>>>>>>>>>>>>>>>>> 4"<<endl;

  return plugin;

  cout<<"-->>>>>>>>>>>>>>>>>>>>>>>>> 5"<<endl;

}
<commit_msg>Fixed typo<commit_after>class AliAnalysisGrid;
const char *dataset   = "";
TString anaLibs = "";
//Int_t iESDfilter       = 1;
Int_t iESDfilter       = 0;
Int_t iAODTagCreation  = 1;
Int_t iAODAddMCBranch  = 0;

//______________________________________________________________________________
void run(
         const char* runtype = "local", // local, proof or grid
         const char *gridmode = "test", // Set the run mode (can be "full", "test", "offline", "submit" or "terminate"). Full & Test work for proof
         const bool bMCtruth = 1, // 1 = MCEvent handler is on (MC truth), 0 = MCEvent handler is off (MC reconstructed/real data)
         const bool bMCphyssel = 1, // 1 = looking at MC truth or reconstructed, 0 = looking at real data
         const Long64_t nentries = 2000, // for local and proof mode, ignored in grid mode. Set to 1234567890 for all events.
         const Long64_t firstentry = 0, // for local and proof mode, ignored in grid mode
         const char *proofdataset = "/alice/data/LHC10c_000120821_p1", // path to dataset on proof cluster, for proof analysis
         const char *proofcluster = "alice-caf.cern.ch", // which proof cluster to use in proof mode
         const char *taskname = "Flowd_PbPb2011"
         )
{
  // check run type
  if(runtype != "local" && runtype != "proof" && runtype != "grid"){
    Printf("\n\tIncorrect run option, check first argument of run macro");
    Printf("\tint runtype = local, proof or grid\n");
    return;
  }
  Printf("%s analysis chosen",runtype);

  gROOT->ProcessLine(".include $ALICE_ROOT/include");

  gSystem->AddIncludePath("-I$ALICE_ROOT/include");
  gSystem->AddIncludePath("-I$ALICE_ROOT/PWGHF/vertexingHF");
  // Load analysis specific libraries
  //=====================================================================

  gSystem->SetIncludePath("-I. -I$ROOTSYS/include -I$ALICE_ROOT -I$ALICE_ROOT/include -I$ALICE_ROOT/ITS -I$ALICE_ROOT/TPC -I$ALICE_ROOT/CONTAINERS -I$ALICE_ROOT/STEER/STEER -I$ALICE_ROOT/STEER/STEERBase -I$ALICE_ROOT/STEER/ESD -I$ALICE_ROOT/STEER/AOD -I$ALICE_ROOT/TRD -I$ALICE_ROOT/macros -I$ALICE_ROOT/ANALYSIS  -I$ALICE_ROOT/OADB -I$ALICE_ROOT/PWGHF -I$ALICE_ROOT/PWGHF/base -I$ALICE_ROOT/PWGHF/vertexingHF -I$ALICE_ROOT/PWG/FLOW/Base -I$ALICE_ROOT/PWG/FLOW/Tasks -g");

  gSystem->Load("libTree.so");
  gSystem->Load("libGeom.so");
  gSystem->Load("libPhysics.so");
  gSystem->Load("libVMC.so");
  gSystem->Load("libMinuit.so");
  gSystem->Load("libSTEERBase.so");
  gSystem->Load("libESD.so");
  gSystem->Load("libAOD.so");
  gSystem->Load("libANALYSIS.so");
  gSystem->Load("libOADB.so");
  gSystem->Load("libANALYSISalice.so");
  gSystem->Load("libCORRFW.so");
  gSystem->Load("libPWGHFbase.so");
  gSystem->Load("libPWGflowBase.so");
  gSystem->Load("libPWGflowTasks.so");
  gSystem->Load("libPWGHFvertexingHF.so");

  // Load analysis specific libraries
  //=====================================================================
  //------ Create AlienPlugin ---------------------
  AliAnalysisGrid *plugin = 0x0;
  TChain *chain = 0x0;
  if (runtype != "local") {
    plugin = CreateAlienHandler(taskname, gridmode, proofcluster, proofdataset);
    if(!plugin) return;
  } else {
    gROOT->LoadMacro("$ALICE_ROOT/PWGCF/Correlations/macros/dphicorrelations/CreateESDChain.C");
    chain = CreateESDChain("ESDs.txt");
  }

  //---- Create the analysis manager
  AliAnalysisManager* mgr = new AliAnalysisManager(taskname);
  if(plugin) mgr->SetGridHandler(plugin);

  //  Input

  AliESDInputHandler* iH = new AliESDInputHandler("handler","handler for my analisys");
  mgr->SetInputEventHandler(iH);

  //--------------------------------------------------------------
  // Other tasks

  // Physics selection
  gROOT->LoadMacro("$ALICE_ROOT/ANALYSIS/macros/AddTaskPhysicsSelection.C");
  AliPhysicsSelectionTask *physSel = AddTaskPhysicsSelection(useMC);
  // Centrality selection
  gROOT->LoadMacro("$ALICE_ROOT/ANALYSIS/macros/AddTaskCentrality.C");
  AliCentralitySelectionTask *taskCentr = AddTaskCentrality();

  gROOT->LoadMacro("$ALICE_ROOT/ANALYSIS/macros/AddTaskPIDResponse.C");
  AliAnalysisTaskPIDResponse *pidTask = AddTaskPIDResponse(useMC);

  gROOT->LoadMacro("./AliAnalysisTaskFlowd.cxx+g");//$ALICE_ROOT/PWGLF/STRANGENESS/Cascades/AliAnalysisTaskCheckCascadePbPb.cxx++g");
  gROOT->LoadMacro("./AddTaskFlowd.C");//$ALICE_ROOT/PWGLF/STRANGENESS/Cascades/macros/AddTaskCheckCascadePbPb.C");
  AliAnalysisTaskFlowd *task = AddTaskFlowd(kTRUE);

  //__________________________________________________________________________
  // Disable debug printouts
  mgr->SetDebugLevel(3);
  AliLog::SetGlobalLogLevel(AliLog::kFatal);
  AliLog::SetGlobalDebugLevel(0);

  //__________________________________________________________________________
  if (!mgr->InitAnalysis()) return;
  mgr->PrintStatus();
  // Start analysis in grid.
  if (runtype == "local")
    mgr->StartAnalysis(runtype,chain,nentries,firstentry);
  else
    mgr->StartAnalysis(runtype,nentries,firstentry);
}

//______________________________________________________________________________
AliAnalysisGrid* CreateAlienHandler(const char *taskname, const char *gridmode, const char *proofcluster, const char *proofdataset)
{
  AliAnalysisAlien *plugin = new AliAnalysisAlien();
  // Set the run mode (can be "full", "test", "offline", "submit" or "terminate")
  plugin->SetRunMode(gridmode);

  // Set versions of used packages

  plugin->SetAPIVersion("V1.1x");
  plugin->SetROOTVersion("v5-34-08");
  plugin->SetAliROOTVersion("vAN-20140915");
  plugin->SetExecutableCommand("aliroot -b -q");

  // Declare input data to be processed.

  // Method 1: Create automatically XML collections using alien 'find' command.
  // Define production directory LFN
  //    plugin->SetGridDataDir("/alice/data/2010/LHC10h");

  // plugin->SetGridDataDir(" /alice/data/2011/LHC11h_2/"); //sim
  // plugin->SetDataPattern("pass2/*AliAOD.root"); // sim

  plugin->SetGridDataDir("/alice/data/2011/LHC11h_2/"); //sim
  plugin->SetDataPattern("/pass2/ESDs/*AliESD.root"); // sim
  plugin->SetRunPrefix("000");   // real data

  Int_t runlist[1]={167693};
  for(Int_t i=0;i<1;i++)
    plugin->AddRunNumber(runlist[i]);

  //    plugin->AddRunNumber(139505);
  //  plugin->AddRunNumber(138652);
  plugin->SetNrunsPerMaster(1);
  plugin->SetOutputToRunNo();

  // Method 2: Declare existing data files (raw collections, xml collections, root file)
  //   plugin->AddDataFile("/alice/data/2008/LHC08c/000057657/raw/Run57657.Merged.RAW.tag.root");

  // Define alien work directory where all files will be copied. Relative to alien $HOME.
  plugin->SetGridWorkingDir(taskname);

  // Declare alien output directory. Relative to working directory.
  plugin->SetGridOutputDir("output"); // In this case will be $HOME/taskname/out

  //  plugin->SetAdditionalLibs("libTree.so libGeom.so libPhysics.so libVMC.so libMinuit.so libSTEERBase.so libESD.so libAOD.so  libANALYSIS.so libOADB.so libANALYSISalice.so libCORRFW.so libPWGHFbase.so libPWGflowBase.so libPWGflowTasks.so libPWGHFvertexingHF.so");

  // plugin->SetAdditionalLibs("libCORRFW.so libPWGHFbase.so libPWGflowBase.so libPWGflowTasks.so libPWGHFvertexingHF.so");

  plugin->SetAnalysisSource("AliAnalysisTaskFlowd.cxx");

  cout<<"-->>>>>>>>>>>>>>>>>>>>>>>>> 1"<<endl;

  // Declare the analysis source files names separated by blancs. To be compiled runtime
  // using ACLiC on the worker nodes.
  //plugin->SetAdditionalLibs("libPWGHFbase.so libPWGflowBase.so libPWGflowTasks.so libPWGHFvertexingHF.so AliAODMuonReplicator0.so");

  cout<<"-->>>>>>>>>>>>>>>>>>>>>>>>> 2"<<endl;
  // plugin->SetAdditionalLibs("libTree.so libGeom.so libPhysics.so libVMC.so libMinuit.so libSTEERBase.so libESD.so libAOD.so libANALYSIS.so libOADB.so libANALYSISalice.so libCORRFW.so libPWGHFbase.so libPWGflowBase.so libPWGflowTasks.so libPWGHFvertexingHF.so");

  // plugin->SetAnalysisSource("AliAnalysisTaskESDMuonFilterO.cxx");
  //plugin->SetAnalysisSource("AliAODMuonReplicator0.cxx");

  // Declare all libraries (other than the default ones for the framework. These will be
  // loaded by the generated analysis macro. Add all extra files (task .cxx/.h) here.
  // plugin->SetAdditionalLibs("AliAODMuonReplicator0_cxx.so");
  // plugin->SetAdditionalLibs("AliAnalysisTaskESDMuonFilterO_cxx.so");

  //questo
  plugin->SetAdditionalLibs("libPWGflowBase.so libPWGflowTasks.so libPWGHFbase.so libPWGHFvertexingHF.so");
  plugin->AddIncludePath("-I. -I$ROOTSYS/include -I$ALICE_ROOT -I$ALICE_ROOT/include -I$ALICE_ROOT/ITS -I$ALICE_ROOT/TPC -I$ALICE_ROOT/CONTAINERS -I$ALICE_ROOT/STEER/STEER -I$ALICE_ROOT/STEER/STEERBase -I$ALICE_ROOT/STEER/ESD -I$ALICE_ROOT/STEER/AOD -I$ALICE_ROOT/TRD -I$ALICE_ROOT/macros -I$ALICE_ROOT/ANALYSIS  -I$ALICE_ROOT/OADB -I$ALICE_ROOT/PWGHF -I$ALICE_ROOT/PWGHF/base -I$ALICE_ROOT/PWGHF/vertexingHF -I$ALICE_ROOT/PWG/FLOW/Base -I$ALICE_ROOT/PWG/FLOW/Tasks -g");

  // plugin->SetAdditionalLibs("AliAODMuonReplicator0.h AliAODMuonReplicator0.cxx");
  // plugin->SetAdditionalLibs("AliAnalysisTaskESDMuonFilterO.h AliAnalysisTaskESDMuonFilterO.cxx");

  //plugin->SetAdditionalLibs("AliAODMuonReplicator0.h AliAODMuonReplicator0.cxx AliAnalysisTaskESDMuonFilterO.h AliAnalysisTaskESDMuonFilterO.cxx");

  cout<<"-->>>>>>>>>>>>>>>>>>>>>>>>> 3"<<endl;

  // plugin->SetAdditionalLibs("AliAODMuonReplicator0.h AliAODMuonReplicator0.cxx");

  // plugin->SetAdditionalLibs("AliAnalysisTaskESDMuonFilterO.h AliAnalysisTaskESDMuonFilterO.cxx");

  // Declare the output file names separated by blancs.
  // (can be like: file.root or file.root@ALICE::Niham::File)
  // To only save certain files, use SetDefaultOutputs(kFALSE), and then
  // SetOutputFiles("list.root other.filename") to choose which files to save
  plugin->SetDefaultOutputs();
  //plugin->SetOutputFiles("list.root");

  // Optionally set a name for the generated analysis macro (default MyAnalysis.C)
  plugin->SetAnalysisMacro(Form("%s.C",taskname));

  // Optionally set maximum number of input files/subjob (default 100, put 0 to ignore)
  plugin->SetSplitMaxInputFileNumber(100);

  // Optionally modify the executable name (default analysis.sh)
  plugin->SetExecutable(Form("%s.sh",taskname));

  // set number of test files to use in "test" mode
  plugin->SetNtestFiles(10);

  // Optionally resubmit threshold.
  plugin->SetMasterResubmitThreshold(90);

  // Optionally set time to live (default 30000 sec)
  plugin->SetTTL(30000);

  // Optionally set input format (default xml-single)
  plugin->SetInputFormat("xml-single");

  // Optionally modify the name of the generated JDL (default analysis.jdl)
  plugin->SetJDLName(Form("%s.jdl",taskname));

  // Optionally modify job price (default 1)
  plugin->SetPrice(1);

  // Optionally modify split mode (default 'se')
  plugin->SetSplitMode("se");

  //----------------------------------------------------------
  //---      PROOF MODE SPECIFIC SETTINGS         ------------
  //----------------------------------------------------------
  // Proof cluster
  plugin->SetProofCluster(proofcluster);
  // Dataset to be used
  plugin->SetProofDataSet(proofdataset);
  // May need to reset proof. Supported modes: 0-no reset, 1-soft, 2-hard
  plugin->SetProofReset(0);
  // May limit number of workers
  plugin->SetNproofWorkers(0);
  // May limit the number of workers per slave
  plugin->SetNproofWorkersPerSlave(1);
  // May use a specific version of root installed in proof
  plugin->SetRootVersionForProof("current");
  // May set the aliroot mode. Check http://aaf.cern.ch/node/83
  plugin->SetAliRootMode("default"); // Loads AF libs by default
  // May request ClearPackages (individual ClearPackage not supported)
  plugin->SetClearPackages(kFALSE);
  // Plugin test mode works only providing a file containing test file locations, used in "local" mode also
  plugin->SetFileForTestMode("files.txt"); // file should contain path name to a local directory containg *ESDs.root etc
  // Request connection to alien upon connection to grid
  plugin->SetProofConnectGrid(kFALSE);

  cout<<"-->>>>>>>>>>>>>>>>>>>>>>>>> 4"<<endl;

  return plugin;

  cout<<"-->>>>>>>>>>>>>>>>>>>>>>>>> 5"<<endl;

}
<|endoftext|>


<commit_before>/*
 * Copyright(c) Sophist Solutions, Inc. 1990-2015.  All rights reserved
 */
#ifndef _Stroika_Foundation_Math_ReBin_inl_
#define _Stroika_Foundation_Math_ReBin_inl_ 1

/*
 ********************************************************************************
 ***************************** Implementation Details ***************************
 ********************************************************************************
 */
#include    "../Debug/Assertions.h"
#include    "../Traversal/Generator.h"
#include    "../Traversal/Partition.h"

#include    "Common.h"

namespace   Stroika {
    namespace   Foundation {
        namespace   Math {
            namespace   ReBin {

                /*
                 ********************************************************************************
                 ********************** Math::ReBin::BasicDataDescriptor ************************
                 ********************************************************************************
                 */
                template    <typename X_TYPE, typename VALUE_TYPE>
                inline  BasicDataDescriptor<X_TYPE, VALUE_TYPE>::BasicDataDescriptor (const ValueType* bucketStart, const ValueType* bucketEnd, XType xStart, XType xEnd)
                    : fBucketDataStart_ (bucketStart)
                    , fBucketDataEnd_ (bucketEnd)
                    , fXStart_ (xStart)
                    , fXEnd_ (xEnd)
                {
                    RequireNotNull (bucketStart);
                    RequireNotNull (bucketEnd);
                    Require (bucketStart < bucketEnd);
                    Require (xStart < xEnd);
                }
                template    <typename X_TYPE, typename VALUE_TYPE>
                inline  typename BasicDataDescriptor<X_TYPE, VALUE_TYPE>::BucketIndexType  BasicDataDescriptor<X_TYPE, VALUE_TYPE>::GetBucketCount () const
                {
                    BucketIndexType result = fBucketDataEnd_ - fBucketDataStart_;
                    Ensure (result > 0);
                    return result;
                }
                template    <typename X_TYPE, typename VALUE_TYPE>
                inline  Traversal::Range<X_TYPE>   BasicDataDescriptor<X_TYPE, VALUE_TYPE>::GetBucketRange (BucketIndexType bucket) const
                {
                    using Traversal::Range;
                    Require (bucket < GetBucketCount ());
                    X_TYPE  kDelta_ = (fXEnd_ - fXStart_) * (static_cast<X_TYPE> (1) / static_cast<X_TYPE> (GetBucketCount ()));
                    X_TYPE  s = fXStart_ + (static_cast<X_TYPE> (bucket) * kDelta_);
                    return Range<X_TYPE> (s, s + kDelta_, Traversal::Openness::eClosed, Traversal::Openness::eOpen);
                }
                template    <typename X_TYPE, typename VALUE_TYPE>
                Traversal::DiscreteRange<typename BasicDataDescriptor<X_TYPE, VALUE_TYPE>::BucketIndexType> BasicDataDescriptor<X_TYPE, VALUE_TYPE>::GetMappedBucketRange (const Traversal::Range<X_TYPE>& xrange) const
                {
                    using Traversal::DiscreteRange;
                    if (xrange.GetUpperBound () < fXStart_) {
                        return DiscreteRange<BucketIndexType> ();
                    }
                    if (xrange.GetLowerBound () > fXEnd_) {
                        return DiscreteRange<BucketIndexType> ();
                    }

                    X_TYPE  kDelta_ = (fXEnd_ - fXStart_) * (static_cast<X_TYPE> (1) / static_cast<X_TYPE> (GetBucketCount ()));

                    // very roughly (quick hack)
                    X_TYPE bucketLowerBound = (xrange.GetLowerBound () - fXStart_) / kDelta_;
                    X_TYPE bucketUpperBound = (xrange.GetUpperBound () - fXStart_) / kDelta_;

                    bucketLowerBound = (bucketLowerBound < 0) ? 0 : bucketLowerBound;
                    bucketUpperBound = (bucketUpperBound < 0) ? 0 : bucketUpperBound;

                    BucketIndexType    bucketLB = Math::PinInRange<BucketIndexType> (static_cast<BucketIndexType> (floor (bucketLowerBound)), 0, GetBucketCount () - 1);
                    BucketIndexType    bucketUB = Math::PinInRange<BucketIndexType> (static_cast<BucketIndexType> (ceil (bucketUpperBound)), bucketLB, GetBucketCount () - 1);

                    return DiscreteRange<BucketIndexType> (bucketLB, bucketUB);
                }
                template    <typename X_TYPE, typename VALUE_TYPE>
                inline  VALUE_TYPE  BasicDataDescriptor<X_TYPE, VALUE_TYPE>::GetValue (BucketIndexType bucket) const
                {
                    Require (bucket < GetBucketCount ());
                    return fBucketDataStart_[bucket];
                }
#if qCompilerAndStdLib_constexpr_Buggy
                template    <typename X_TYPE, typename VALUE_TYPE>
                const VALUE_TYPE BasicDataDescriptor<X_TYPE, VALUE_TYPE>::kZero = 0;
#endif

                /*
                 ********************************************************************************
                 ***************** Math::ReBin::UpdatableDataDescriptor *************************
                 ********************************************************************************
                 */
                template    <typename X_TYPE, typename VALUE_TYPE>
                inline  UpdatableDataDescriptor<X_TYPE, VALUE_TYPE>::UpdatableDataDescriptor (VALUE_TYPE* bucketStart, VALUE_TYPE* bucketEnd, X_TYPE xStart, X_TYPE xEnd)
                    : inherited (bucketStart, bucketEnd, xStart, xEnd)
                {
                }
                template    <typename X_TYPE, typename VALUE_TYPE>
                inline  void  UpdatableDataDescriptor<X_TYPE, VALUE_TYPE>::AccumulateValue (typename inherited::BucketIndexType bucket, VALUE_TYPE delta)
                {
                    Require (bucket < inherited::GetBucketCount ());
                    VALUE_TYPE*  updatableStart = const_cast<VALUE_TYPE*> (inherited::fBucketDataStart_);
                    updatableStart[bucket] += delta;
                }
                template    <typename X_TYPE, typename VALUE_TYPE>
                inline  void    UpdatableDataDescriptor<X_TYPE, VALUE_TYPE>::ZeroBuckets ()
                {
                    VALUE_TYPE*  updatableStart = const_cast<VALUE_TYPE*> (inherited::fBucketDataStart_);
                    for (VALUE_TYPE* i = updatableStart; i != inherited::fBucketDataEnd_; ++i) {
                        *i = inherited::kZero;
                    }
                }

                /*
                 ********************************************************************************
                 ************************************* PRIVATE_ *********************************
                 ********************************************************************************
                 */
                namespace PRIVATE_ {
                    template    <typename DATA_DESCRIPTOR_TYPE>
                    void    CheckRebinDataDescriptorInvariant_ (const DATA_DESCRIPTOR_TYPE& d)
                    {
#if     qDebug
                        using   namespace   Traversal;
                        using   Memory::Optional;
                        using   BucketIndexType = typename DATA_DESCRIPTOR_TYPE::BucketIndexType;
                        using   XType = typename DATA_DESCRIPTOR_TYPE::XType;
                        auto myContext = shared_ptr<BucketIndexType> (new BucketIndexType (0));
                        auto bucketCount = d.GetBucketCount ();
                        auto getNext = [myContext, bucketCount, d] () -> Optional<Range<XType>> {
                            Optional<Range<XType>>   result;
                            if (*myContext < bucketCount)
                            {
                                result = d.GetBucketRange (*myContext);
                                (*myContext)++;
                            }
                            return result;
                        };
                        Assert (IsPartition (CreateGenerator<Range<XType>> (getNext)));
#endif
                    }
                }

                /*
                 ********************************************************************************
                 ********************************** Math::ReBin *********************************
                 ********************************************************************************
                 */
                template    <typename   SRC_DATA_DESCRIPTOR, typename TRG_DATA_DESCRIPTOR>
                void    ReBin (
                    const SRC_DATA_DESCRIPTOR& srcData,
                    TRG_DATA_DESCRIPTOR* trgData
                )
                {
                    RequireNotNull (trgData);

                    using   namespace Traversal;
                    /*
                     *  OLD OBSOLETE Algorithm:
                     *      Two iterators - one marking (start/end of target buckets), and one marking current
                     *      src bucket. Iterate over outer buckets. Move contents to new bucket. And adjust new
                     *      iterators. When they overlap and must advance - proportionally add to bucket,
                     *      advance and add rest to next target bucket.
                     *
                     *      This is probably more efficent than the algorithm below, but trickier to generalize
                     *      so we can have differently scaled source buckets.
                     */

                    /*
                     *  By default, zero all target buckets, but you could override that in the TRG argument
                     *  to avoid zeroing (say to accumulate multiple sources)
                     */
                    trgData->ZeroBuckets ();

#if     qDebug
                    PRIVATE_::CheckRebinDataDescriptorInvariant_ (srcData);
                    PRIVATE_::CheckRebinDataDescriptorInvariant_ (*trgData);
#endif

                    /*
                     *  x               0    1    2    3    4    5
                     *
                     *  SRC-BUCKETS:    |    |    |    |    |    |
                     *  TRG-BUCKETS:    |      |      |      |
                     *
                     *  Iterate over each source bucket. It represnts data from its sourceXStart, to srcXEnd (bucket X domain)
                     *  all data spread evently.
                     *
                     *  See where that start x/endx map to in y buckets, and spread it over them. Assume that in the TARGET
                     *  the buckets are contiguous.
                     *
                     *  For each one source bucket, put part into current ti (proportional), and put reset into next
                     *  ti (proportional).
                     */
                    size_t      srcBucketCount = srcData.GetBucketCount ();
                    for (size_t srcBucketIdx = 0; srcBucketIdx < srcBucketCount; ++srcBucketIdx) {
                        Range<typename SRC_DATA_DESCRIPTOR::XType>  curSrcBucketX       =   srcData.GetBucketRange(srcBucketIdx);
                        auto                                        curSrcBucketXWidth  =   curSrcBucketX.GetDistanceSpanned ();
                        typename SRC_DATA_DESCRIPTOR::ValueType     thisSrcBucketValue  =   srcData.GetValue(srcBucketIdx);

                        Assert (curSrcBucketXWidth >= 0);   // can ever be zero?

                        // Check special value of zero so we dont waste time spreading zeros around
                        if (thisSrcBucketValue != SRC_DATA_DESCRIPTOR::kZero and curSrcBucketXWidth != 0) {
                            /*
                             *  find range of target buckets to distribute value.
                             *
                             *  Each bucket returned may have little overall contribution from the source bucket. We look at
                             *  the degree of overlap.
                             */
                            for (auto targetBucket : trgData->GetMappedBucketRange (curSrcBucketX).Elements ()) {
                                Range<typename SRC_DATA_DESCRIPTOR::XType>  trgBucketIntersectRange =   trgData->GetBucketRange(targetBucket).Intersection (curSrcBucketX);
                                auto                                        trgBucketXWidth         =   trgBucketIntersectRange.GetDistanceSpanned ();
                                trgData->AccumulateValue (targetBucket, thisSrcBucketValue * (trgBucketXWidth / curSrcBucketXWidth));
                            }
                        }
                    }
                }
                template    <typename SRC_BUCKET_TYPE, typename TRG_BUCKET_TYPE, typename X_OFFSET_TYPE>
                void    ReBin (
                    const SRC_BUCKET_TYPE* srcStart, const SRC_BUCKET_TYPE* srcEnd,
                    TRG_BUCKET_TYPE* trgStart, TRG_BUCKET_TYPE* trgEnd
                )
                {
                    using   SRC_DATA_DESCRIPTOR     =   BasicDataDescriptor<X_OFFSET_TYPE, SRC_BUCKET_TYPE>;
                    using   TRG_DATA_DESCRIPTOR     =   UpdatableDataDescriptor<X_OFFSET_TYPE, TRG_BUCKET_TYPE>;

                    SRC_DATA_DESCRIPTOR srcData (srcStart, srcEnd, 1, 2);
                    TRG_DATA_DESCRIPTOR trgData (trgStart, trgEnd, 1, 2);
                    ReBin (srcData, &trgData);
                }

            }
        }
    }
}
#endif  /*_Stroika_Foundation_Math_ReBin_inl_*/
<commit_msg>cleanup Rebin code<commit_after>/*
 * Copyright(c) Sophist Solutions, Inc. 1990-2015.  All rights reserved
 */
#ifndef _Stroika_Foundation_Math_ReBin_inl_
#define _Stroika_Foundation_Math_ReBin_inl_ 1

/*
 ********************************************************************************
 ***************************** Implementation Details ***************************
 ********************************************************************************
 */
#include    "../Debug/Assertions.h"
#include    "../Traversal/Generator.h"
#include    "../Traversal/Partition.h"

#include    "Common.h"

namespace   Stroika {
    namespace   Foundation {
        namespace   Math {
            namespace   ReBin {

                /*
                 ********************************************************************************
                 ********************** Math::ReBin::BasicDataDescriptor ************************
                 ********************************************************************************
                 */
                template    <typename X_TYPE, typename VALUE_TYPE>
                inline  BasicDataDescriptor<X_TYPE, VALUE_TYPE>::BasicDataDescriptor (const ValueType* bucketStart, const ValueType* bucketEnd, XType xStart, XType xEnd)
                    : fBucketDataStart_ (bucketStart)
                    , fBucketDataEnd_ (bucketEnd)
                    , fXStart_ (xStart)
                    , fXEnd_ (xEnd)
                {
                    RequireNotNull (bucketStart);
                    RequireNotNull (bucketEnd);
                    Require (bucketStart < bucketEnd);
                    Require (xStart < xEnd);
                }
                template    <typename X_TYPE, typename VALUE_TYPE>
                inline  typename BasicDataDescriptor<X_TYPE, VALUE_TYPE>::BucketIndexType  BasicDataDescriptor<X_TYPE, VALUE_TYPE>::GetBucketCount () const
                {
                    BucketIndexType result = fBucketDataEnd_ - fBucketDataStart_;
                    Ensure (result > 0);
                    return result;
                }
                template    <typename X_TYPE, typename VALUE_TYPE>
                inline  Traversal::Range<X_TYPE>   BasicDataDescriptor<X_TYPE, VALUE_TYPE>::GetBucketRange (BucketIndexType bucket) const
                {
                    using Traversal::Range;
                    Require (bucket < GetBucketCount ());
                    X_TYPE  kDelta_ = (fXEnd_ - fXStart_) * (static_cast<X_TYPE> (1) / static_cast<X_TYPE> (GetBucketCount ()));
                    X_TYPE  s = fXStart_ + (static_cast<X_TYPE> (bucket) * kDelta_);
                    return Range<X_TYPE> (s, s + kDelta_, Traversal::Openness::eClosed, Traversal::Openness::eOpen);
                }
                template    <typename X_TYPE, typename VALUE_TYPE>
                Traversal::DiscreteRange<typename BasicDataDescriptor<X_TYPE, VALUE_TYPE>::BucketIndexType> BasicDataDescriptor<X_TYPE, VALUE_TYPE>::GetMappedBucketRange (const Traversal::Range<X_TYPE>& xrange) const
                {
                    using Traversal::DiscreteRange;
                    if (xrange.GetUpperBound () < fXStart_) {
                        return DiscreteRange<BucketIndexType> ();
                    }
                    if (xrange.GetLowerBound () > fXEnd_) {
                        return DiscreteRange<BucketIndexType> ();
                    }

                    X_TYPE  kDelta_ = (fXEnd_ - fXStart_) * (static_cast<X_TYPE> (1) / static_cast<X_TYPE> (GetBucketCount ()));

                    // very roughly (quick hack)
                    X_TYPE bucketLowerBound = (xrange.GetLowerBound () - fXStart_) / kDelta_;
                    X_TYPE bucketUpperBound = (xrange.GetUpperBound () - fXStart_) / kDelta_;

                    bucketLowerBound = (bucketLowerBound < 0) ? 0 : bucketLowerBound;
                    bucketUpperBound = (bucketUpperBound < 0) ? 0 : bucketUpperBound;

                    BucketIndexType    bucketLB = Math::PinInRange<BucketIndexType> (static_cast<BucketIndexType> (floor (bucketLowerBound)), 0, GetBucketCount () - 1);
                    BucketIndexType    bucketUB = Math::PinInRange<BucketIndexType> (static_cast<BucketIndexType> (ceil (bucketUpperBound)), bucketLB, GetBucketCount () - 1);

                    return DiscreteRange<BucketIndexType> (bucketLB, bucketUB);
                }
                template    <typename X_TYPE, typename VALUE_TYPE>
                inline  VALUE_TYPE  BasicDataDescriptor<X_TYPE, VALUE_TYPE>::GetValue (BucketIndexType bucket) const
                {
                    Require (bucket < GetBucketCount ());
                    return fBucketDataStart_[bucket];
                }
#if qCompilerAndStdLib_constexpr_Buggy
                template    <typename X_TYPE, typename VALUE_TYPE>
                const VALUE_TYPE BasicDataDescriptor<X_TYPE, VALUE_TYPE>::kZero = 0;
#endif

                /*
                 ********************************************************************************
                 ***************** Math::ReBin::UpdatableDataDescriptor *************************
                 ********************************************************************************
                 */
                template    <typename X_TYPE, typename VALUE_TYPE>
                inline  UpdatableDataDescriptor<X_TYPE, VALUE_TYPE>::UpdatableDataDescriptor (VALUE_TYPE* bucketStart, VALUE_TYPE* bucketEnd, X_TYPE xStart, X_TYPE xEnd)
                    : inherited (bucketStart, bucketEnd, xStart, xEnd)
                {
                }
                template    <typename X_TYPE, typename VALUE_TYPE>
                inline  void  UpdatableDataDescriptor<X_TYPE, VALUE_TYPE>::AccumulateValue (typename inherited::BucketIndexType bucket, VALUE_TYPE delta)
                {
                    Require (bucket < inherited::GetBucketCount ());
                    VALUE_TYPE*  updatableStart = const_cast<VALUE_TYPE*> (inherited::fBucketDataStart_);
                    updatableStart[bucket] += delta;
                }
                template    <typename X_TYPE, typename VALUE_TYPE>
                inline  void    UpdatableDataDescriptor<X_TYPE, VALUE_TYPE>::ZeroBuckets ()
                {
                    VALUE_TYPE*  updatableStart = const_cast<VALUE_TYPE*> (inherited::fBucketDataStart_);
                    for (VALUE_TYPE* i = updatableStart; i != inherited::fBucketDataEnd_; ++i) {
                        *i = inherited::kZero;
                    }
                }

                /*
                 ********************************************************************************
                 ************************************* PRIVATE_ *********************************
                 ********************************************************************************
                 */
                namespace PRIVATE_ {
                    template    <typename DATA_DESCRIPTOR_TYPE>
                    void    CheckRebinDataDescriptorInvariant_ (const DATA_DESCRIPTOR_TYPE& d)
                    {
#if     qDebug
                        using   namespace   Traversal;
                        using   Memory::Optional;
                        using   BucketIndexType = typename DATA_DESCRIPTOR_TYPE::BucketIndexType;
                        using   XType = typename DATA_DESCRIPTOR_TYPE::XType;
                        auto myContext = shared_ptr<BucketIndexType> (new BucketIndexType (0));
                        auto bucketCount = d.GetBucketCount ();
                        auto getNext = [myContext, bucketCount, d] () -> Optional<Range<XType>> {
                            Optional<Range<XType>>   result;
                            if (*myContext < bucketCount)
                            {
                                result = d.GetBucketRange (*myContext);
                                (*myContext)++;
                            }
                            return result;
                        };
                        Assert (IsPartition (CreateGenerator<Range<XType>> (getNext)));
#endif
                    }
                }

                /*
                 ********************************************************************************
                 ********************************** Math::ReBin *********************************
                 ********************************************************************************
                 */
                template    <typename   SRC_DATA_DESCRIPTOR, typename TRG_DATA_DESCRIPTOR>
                void    ReBin (
                    const SRC_DATA_DESCRIPTOR& srcData,
                    TRG_DATA_DESCRIPTOR* trgData
                )
                {
                    RequireNotNull (trgData);

                    using   namespace Traversal;
                    using   BucketIndexType =   typename SRC_DATA_DESCRIPTOR::BucketIndexType;

                    /*
                     *  OLD OBSOLETE Algorithm:
                     *      Two iterators - one marking (start/end of target buckets), and one marking current
                     *      src bucket. Iterate over outer buckets. Move contents to new bucket. And adjust new
                     *      iterators. When they overlap and must advance - proportionally add to bucket,
                     *      advance and add rest to next target bucket.
                     *
                     *      This is probably more efficent than the algorithm below, but trickier to generalize
                     *      so we can have differently scaled source buckets.
                     */

                    /*
                     *  By default, zero all target buckets, but you could override that in the TRG argument
                     *  to avoid zeroing (say to accumulate multiple sources)
                     */
                    trgData->ZeroBuckets ();

#if     qDebug
                    PRIVATE_::CheckRebinDataDescriptorInvariant_ (srcData);
                    PRIVATE_::CheckRebinDataDescriptorInvariant_ (*trgData);
#endif

                    /*
                     *  x               0    1    2    3    4    5
                     *
                     *  SRC-BUCKETS:    |    |    |    |    |    |
                     *  TRG-BUCKETS:    |      |      |      |
                     *
                     *  Iterate over each source bucket. It represnts data from its sourceXStart, to srcXEnd (bucket X domain)
                     *  all data spread evently.
                     *
                     *  See where that start x/endx map to in y buckets, and spread it over them. Assume that in the TARGET
                     *  the buckets are contiguous.
                     *
                     *  For each one source bucket, put part into current ti (proportional), and put reset into next
                     *  ti (proportional).
                     */
                    BucketIndexType      srcBucketCount = srcData.GetBucketCount ();
                    for (BucketIndexType srcBucketIdx = 0; srcBucketIdx < srcBucketCount; ++srcBucketIdx) {
                        Range<typename SRC_DATA_DESCRIPTOR::XType>  curSrcBucketX       =   srcData.GetBucketRange(srcBucketIdx);
                        auto                                        curSrcBucketXWidth  =   curSrcBucketX.GetDistanceSpanned ();
                        typename SRC_DATA_DESCRIPTOR::ValueType     thisSrcBucketValue  =   srcData.GetValue(srcBucketIdx);

                        Assert (curSrcBucketXWidth >= 0);   // can ever be zero?

                        // Check special value of zero so we dont waste time spreading zeros around
                        if (thisSrcBucketValue != SRC_DATA_DESCRIPTOR::kZero and curSrcBucketXWidth != 0) {
                            /*
                             *  find range of target buckets to distribute value.
                             *
                             *  Each bucket returned may have little overall contribution from the source bucket. We look at
                             *  the degree of overlap.
                             */
                            for (auto targetBucket : trgData->GetMappedBucketRange (curSrcBucketX).Elements ()) {
                                Range<typename SRC_DATA_DESCRIPTOR::XType>  trgBucketIntersectRange =   trgData->GetBucketRange(targetBucket).Intersection (curSrcBucketX);
                                auto                                        trgBucketXWidth         =   trgBucketIntersectRange.GetDistanceSpanned ();
                                trgData->AccumulateValue (targetBucket, thisSrcBucketValue * (trgBucketXWidth / curSrcBucketXWidth));
                            }
                        }
                    }
                }
                template    <typename SRC_BUCKET_TYPE, typename TRG_BUCKET_TYPE, typename X_OFFSET_TYPE>
                void    ReBin (
                    const SRC_BUCKET_TYPE* srcStart, const SRC_BUCKET_TYPE* srcEnd,
                    TRG_BUCKET_TYPE* trgStart, TRG_BUCKET_TYPE* trgEnd
                )
                {
                    using   SRC_DATA_DESCRIPTOR     =   BasicDataDescriptor<X_OFFSET_TYPE, SRC_BUCKET_TYPE>;
                    using   TRG_DATA_DESCRIPTOR     =   UpdatableDataDescriptor<X_OFFSET_TYPE, TRG_BUCKET_TYPE>;

                    SRC_DATA_DESCRIPTOR srcData (srcStart, srcEnd, 1, 2);
                    TRG_DATA_DESCRIPTOR trgData (trgStart, trgEnd, 1, 2);
                    ReBin (srcData, &trgData);
                }

            }
        }
    }
}
#endif  /*_Stroika_Foundation_Math_ReBin_inl_*/
<|endoftext|>


<commit_before>#if HYRISE_NUMA_SUPPORT

#include <chrono>
#include <memory>
#include <string>
#include <thread>
#include <utility>
#include <vector>

#include "../base_test.hpp"
#include "gtest/gtest.h"

#include "../lib/scheduler/current_scheduler.hpp"
#include "../lib/scheduler/node_queue_scheduler.hpp"
#include "../lib/scheduler/topology.hpp"
#include "../lib/storage/chunk.hpp"
#include "../lib/storage/chunk_encoder.hpp"
#include "../lib/storage/numa_placement_manager.hpp"
#include "../lib/storage/storage_manager.hpp"
#include "../lib/storage/table.hpp"
#include "../lib/storage/value_column.hpp"
#include "../lib/tasks/migration_preparation_task.hpp"
#include "../lib/types.hpp"

namespace opossum {

class NUMAPlacementTest : public BaseTest {
 protected:
  void SetUp() override {
    NUMAPlacementManager::get().resume();

    const auto table = create_table(_chunk_count, 1000);
    StorageManager::get().add_table("table", table);

    _node_count = Topology::get().nodes().size();
  }

  // Returns a vector that contains the counts of chunks per node.
  // The index of the vector represents the NodeID.
  std::vector<size_t> count_chunks_by_node(const std::shared_ptr<Table>& table) {
    std::vector<size_t> result(_node_count);
    const auto chunk_count = table->chunk_count();
    for (ChunkID i = ChunkID(0); i < chunk_count; i++) {
      const auto chunk = table->get_chunk(i);
      const auto node_id = MigrationPreparationTask::get_node_id(chunk->get_allocator());
      result.at(node_id)++;
    }
    return result;
  }

  // Creates a table with a single column and increasing integers modulo 1000.
  std::shared_ptr<Table> create_table(size_t num_chunks, size_t num_rows_per_chunk) {
    auto table = std::make_shared<Table>(TableColumnDefinitions{{"a", DataType::Int, false}}, TableType::Data,
                                         num_rows_per_chunk, UseMvcc::Yes);

    for (size_t i = 0; i < num_chunks; i++) {
      ChunkColumns columns;

      const auto alloc = PolymorphicAllocator<Chunk>(Topology::get().get_memory_resource(0));
      auto value_column = std::allocate_shared<ValueColumn<int>>(alloc, alloc);
      auto& values = value_column->values();
      values.reserve(num_rows_per_chunk);
      for (size_t row = 0; row < num_rows_per_chunk; row++) {
        values.push_back(static_cast<int>(row % 1000));
      }
      columns.push_back(value_column);
      table->append_chunk(columns, alloc, std::make_shared<ChunkAccessCounter>(alloc));
    }
    ChunkEncoder::encode_all_chunks(table);
    return table;
  }

  size_t _node_count;
  static constexpr size_t _chunk_count = 10;
};

// Tests the chunk migration algorithm without the integrated loop
// of NUMAPlacementManager.
TEST_F(NUMAPlacementTest, ChunkMigration) {
  const auto& table = StorageManager::get().get_table("table");
  const auto& options = NUMAPlacementManager::get().options();

  // Set mocked chunk access times
  for (ChunkID i = ChunkID(0); i < table->chunk_count(); i++) {
    auto chunk = table->get_chunk(i);
    for (size_t j = 0; j < 100; j++) {
      chunk->access_counter()->increment(100);
      chunk->access_counter()->process();
    }
  }

  // Initially all chunks should reside on node 0
  EXPECT_EQ(count_chunks_by_node(table)[0], _chunk_count);

  // Run two migrations
  for (size_t i = 0; i < 2; i++) {
    MigrationPreparationTask(options).execute();
  }

  if (_node_count > 1) {
    // At least one chunk has been migrated away from node 0.
    EXPECT_LT(count_chunks_by_node(table)[0], _chunk_count);
  }
}

// Tests the integrated loop of NUMAPlacementManager.
TEST_F(NUMAPlacementTest, IntegratedLoopTest) {
  const auto& table = StorageManager::get().get_table("table");
  const auto& options = NUMAPlacementManager::get().options();

  // Initially all chunks should reside on node 0
  EXPECT_EQ(count_chunks_by_node(table)[0], _chunk_count);

  // Start the loop
  NUMAPlacementManager::get().resume();

  // Simulate chunk accesses, ChunkMetricsCollectionTask should pick
  // those up
  for (size_t j = 0; j < 150; j++) {
    for (ChunkID i = ChunkID(0); i < table->chunk_count(); i++) {
      auto chunk = table->get_chunk(i);
      chunk->access_counter()->increment(100);
    }
    std::this_thread::sleep_for(options.counter_history_interval);
  }

  // MigrationPreparationTask and chunk migration should have run at least once by now

  if (_node_count > 1) {
    // At least one chunk has been migrated away from node 1.
    EXPECT_LT(count_chunks_by_node(table)[0], _chunk_count);
  }

  // Stop the loop
  NUMAPlacementManager::get().pause();
}

}  // namespace opossum

#endif
<commit_msg>Disable NUMAPlacementTest (#992)<commit_after>#if HYRISE_NUMA_SUPPORT

#include <chrono>
#include <memory>
#include <string>
#include <thread>
#include <utility>
#include <vector>

#include "../base_test.hpp"
#include "gtest/gtest.h"

#include "../lib/scheduler/current_scheduler.hpp"
#include "../lib/scheduler/node_queue_scheduler.hpp"
#include "../lib/scheduler/topology.hpp"
#include "../lib/storage/chunk.hpp"
#include "../lib/storage/chunk_encoder.hpp"
#include "../lib/storage/numa_placement_manager.hpp"
#include "../lib/storage/storage_manager.hpp"
#include "../lib/storage/table.hpp"
#include "../lib/storage/value_column.hpp"
#include "../lib/tasks/migration_preparation_task.hpp"
#include "../lib/types.hpp"

namespace opossum {

class NUMAPlacementTest : public BaseTest {
 protected:
  void SetUp() override {
    NUMAPlacementManager::get().resume();

    const auto table = create_table(_chunk_count, 1000);
    StorageManager::get().add_table("table", table);

    _node_count = Topology::get().nodes().size();
  }

  // Returns a vector that contains the counts of chunks per node.
  // The index of the vector represents the NodeID.
  std::vector<size_t> count_chunks_by_node(const std::shared_ptr<Table>& table) {
    std::vector<size_t> result(_node_count);
    const auto chunk_count = table->chunk_count();
    for (ChunkID i = ChunkID(0); i < chunk_count; i++) {
      const auto chunk = table->get_chunk(i);
      const auto node_id = MigrationPreparationTask::get_node_id(chunk->get_allocator());
      result.at(node_id)++;
    }
    return result;
  }

  // Creates a table with a single column and increasing integers modulo 1000.
  std::shared_ptr<Table> create_table(size_t num_chunks, size_t num_rows_per_chunk) {
    auto table = std::make_shared<Table>(TableColumnDefinitions{{"a", DataType::Int, false}}, TableType::Data,
                                         num_rows_per_chunk, UseMvcc::Yes);

    for (size_t i = 0; i < num_chunks; i++) {
      ChunkColumns columns;

      const auto alloc = PolymorphicAllocator<Chunk>(Topology::get().get_memory_resource(0));
      auto value_column = std::allocate_shared<ValueColumn<int>>(alloc, alloc);
      auto& values = value_column->values();
      values.reserve(num_rows_per_chunk);
      for (size_t row = 0; row < num_rows_per_chunk; row++) {
        values.push_back(static_cast<int>(row % 1000));
      }
      columns.push_back(value_column);
      table->append_chunk(columns, alloc, std::make_shared<ChunkAccessCounter>(alloc));
    }
    ChunkEncoder::encode_all_chunks(table);
    return table;
  }

  size_t _node_count;
  static constexpr size_t _chunk_count = 10;
};

// Tests the chunk migration algorithm without the integrated loop
// of NUMAPlacementManager.
TEST_F(NUMAPlacementTest, /* #646 */ DISABLED_ChunkMigration) {
  const auto& table = StorageManager::get().get_table("table");
  const auto& options = NUMAPlacementManager::get().options();

  // Set mocked chunk access times
  for (ChunkID i = ChunkID(0); i < table->chunk_count(); i++) {
    auto chunk = table->get_chunk(i);
    for (size_t j = 0; j < 100; j++) {
      chunk->access_counter()->increment(100);
      chunk->access_counter()->process();
    }
  }

  // Initially all chunks should reside on node 0
  EXPECT_EQ(count_chunks_by_node(table)[0], _chunk_count);

  // Run two migrations
  for (size_t i = 0; i < 2; i++) {
    MigrationPreparationTask(options).execute();
  }

  if (_node_count > 1) {
    // At least one chunk has been migrated away from node 0.
    EXPECT_LT(count_chunks_by_node(table)[0], _chunk_count);
  }
}

// Tests the integrated loop of NUMAPlacementManager.
TEST_F(NUMAPlacementTest, /* #646 */ DISABLED_IntegratedLoopTest) {
  const auto& table = StorageManager::get().get_table("table");
  const auto& options = NUMAPlacementManager::get().options();

  // Initially all chunks should reside on node 0
  EXPECT_EQ(count_chunks_by_node(table)[0], _chunk_count);

  // Start the loop
  NUMAPlacementManager::get().resume();

  // Simulate chunk accesses, ChunkMetricsCollectionTask should pick
  // those up
  for (size_t j = 0; j < 150; j++) {
    for (ChunkID i = ChunkID(0); i < table->chunk_count(); i++) {
      auto chunk = table->get_chunk(i);
      chunk->access_counter()->increment(100);
    }
    std::this_thread::sleep_for(options.counter_history_interval);
  }

  // MigrationPreparationTask and chunk migration should have run at least once by now

  if (_node_count > 1) {
    // At least one chunk has been migrated away from node 1.
    EXPECT_LT(count_chunks_by_node(table)[0], _chunk_count);
  }

  // Stop the loop
  NUMAPlacementManager::get().pause();
}

}  // namespace opossum

#endif
<|endoftext|>


<commit_before>/*
 * Integration test suite for flow modifications.
 *
 * Copyright (c) 2014 Cisco Systems, Inc. and others.  All rights reserved.
 *
 * This program and the accompanying materials are made available under the
 * terms of the Eclipse Public License v1.0 which accompanies this distribution,
 * and is available at http://www.eclipse.org/legal/epl-v10.html
 */

#include <vector>
#include <boost/test/unit_test.hpp>
#include <boost/assign/list_inserter.hpp>
#include <boost/bind.hpp>
#include "logging.h"

#include "ovs.h"
#include "ConnectionFixture.h"
#include "FlowReader.h"
#include "FlowExecutor.h"
#include "ActionBuilder.h"

using namespace std;
using namespace boost;
using namespace ovsagent;

class BlockingFlowReader {
public:
    BlockingFlowReader(SwitchConnection *c) {
        conn = c;
        reader.installListenersForConnection(conn);
        cb = boost::bind(&BlockingFlowReader::gotFlow, this, _1, _2);
        gcb = boost::bind(&BlockingFlowReader::gotGroup, this, _1, _2);
    }
    ~BlockingFlowReader() {
        reader.uninstallListenersForConnection(conn);
    }

    void gotFlow(const FlowEntryList& flows, bool done) {
        recvFlows.insert(recvFlows.end(), flows.begin(), flows.end());
        replyDone = done;
    }
    void gotGroup(const GroupEdit::EntryList& groups, bool done) {
        recvGroups.insert(recvGroups.end(), groups.begin(), groups.end());
        replyDone = done;
    }

    void GetFlows(uint8_t tableId, FlowEntryList& flows) {
        recvFlows.clear();
        replyDone = false;
        reader.getFlows(tableId, cb);
        while (replyDone == false) {
            sleep(1);
        }
        flows.swap(recvFlows);
    }

    void GetGroups(GroupEdit::EntryList& groups) {
        recvGroups.clear();
        replyDone = false;
        reader.getGroups(gcb);
        while (replyDone == false) {
            sleep(1);
        }
        groups.swap(recvGroups);
    }

    SwitchConnection *conn;
    FlowReader reader;
    FlowReader::FlowCb cb;
    FlowEntryList recvFlows;
    FlowReader::GroupCb gcb;
    GroupEdit::EntryList recvGroups;
    bool replyDone;
};

class FlowModFixture : public ConnectionFixture,
                       public OnConnectListener {
public:
    FlowModFixture() : conn(testSwitchName), rdr(&conn), connectDone(false) {
        fexec.InstallListenersForConnection(&conn);
        conn.RegisterOnConnectListener(this);
        createTestFlows();
    }
    ~FlowModFixture() {
        conn.UnregisterOnConnectListener(this);
        fexec.UninstallListenersForConnection(&conn);
    }

    /** Interface: OnConnectListener */
    void Connected(SwitchConnection*) {
        connectDone = true;
    }

    void createTestFlows();

    void compareFlows(const FlowEntry& lhs, const FlowEntry& rhs);
    void removeDefaultFlows(FlowEntryList& newFlows);

    SwitchConnection conn;
    BlockingFlowReader rdr;
    FlowExecutor fexec;
    FlowEntryList testFlows;
    bool connectDone;
};

BOOST_AUTO_TEST_SUITE(flowmod_test)

BOOST_FIXTURE_TEST_CASE(simple_mod, FlowModFixture) {
    BOOST_REQUIRE(!conn.Connect(OFP13_VERSION));
    WAIT_FOR(connectDone == true, 5);

    FlowEdit fe;
    FlowEntryList flows;

    /* add */
    assign::push_back(fe.edits)(FlowEdit::ADD, testFlows[0]);
    BOOST_CHECK(fexec.Execute(fe));
    rdr.GetFlows(0, flows);
    removeDefaultFlows(flows);
    BOOST_CHECK(flows.size() == 1);
    compareFlows(*testFlows[0], *flows[0]);
    flows.clear();

    /* modify */
    fe.edits.clear();
    assign::push_back(fe.edits)(FlowEdit::MOD, testFlows[1]);
    BOOST_CHECK(fexec.Execute(fe));
    rdr.GetFlows(0, flows);
    removeDefaultFlows(flows);
    BOOST_CHECK(flows.size() == 1);
    compareFlows(*testFlows[1], *flows[0]);
    flows.clear();

    /* delete */
    fe.edits.clear();
    assign::push_back(fe.edits)(FlowEdit::DEL, testFlows[1]);
    BOOST_CHECK(fexec.Execute(fe));
    rdr.GetFlows(0, flows);
    removeDefaultFlows(flows);
    BOOST_CHECK(flows.size() == 0);
    flows.clear();
}

static
void addBucket(uint32_t bucketId, GroupEdit::Entry& entry) {
    ofputil_bucket *bkt = (ofputil_bucket *)malloc(sizeof(ofputil_bucket));
    bkt->weight = 1;
    bkt->bucket_id = bucketId;
    bkt->watch_port = OFPP_ANY;
    bkt->watch_group = OFPG11_ANY;

    ActionBuilder ab;
    ab.output(bucketId);
    ab.build(bkt);
    list_push_back(&entry->mod->buckets, &bkt->list_node);
}

BOOST_FIXTURE_TEST_CASE(group_mod, FlowModFixture) {
    BOOST_REQUIRE(!conn.Connect(OFP13_VERSION));
    WAIT_FOR(connectDone == true, 5);

    GroupEdit::Entry entryIn1(new GroupEdit::GroupMod());
    entryIn1->mod->command = OFPGC11_ADD;
    entryIn1->mod->group_id = 0;
    addBucket(10, entryIn1);
    addBucket(20, entryIn1);
    addBucket(30, entryIn1);

    GroupEdit::Entry entryIn1_1(new GroupEdit::GroupMod());
    entryIn1_1->mod->command = OFPGC11_MODIFY;
    entryIn1_1->mod->group_id = 0;
    addBucket(10, entryIn1_1);
    BOOST_CHECK(!GroupEdit::groupEq(entryIn1, entryIn1_1));

    GroupEdit::Entry entryIn2(new GroupEdit::GroupMod());
    entryIn2->mod->command = OFPGC11_ADD;
    entryIn2->mod->group_id = 1;
    addBucket(15, entryIn2);
    BOOST_CHECK(!GroupEdit::groupEq(entryIn1, entryIn2));

    GroupEdit gedit;
    gedit.edits.push_back(entryIn1);
    gedit.edits.push_back(entryIn2);
    BOOST_CHECK(fexec.Execute(gedit));

    GroupEdit::EntryList gl;
    rdr.GetGroups(gl);
    BOOST_CHECK(gl.size() == 2);
    BOOST_CHECK(GroupEdit::groupEq(gl[0], entryIn1));
    BOOST_CHECK(GroupEdit::groupEq(gl[1], entryIn2));

    gedit.edits.clear();
    gedit.edits.push_back(entryIn1_1);
    BOOST_CHECK(fexec.Execute(gedit));
    gl.clear();
    rdr.GetGroups(gl);
    BOOST_CHECK(gl.size() == 2);
    BOOST_CHECK(GroupEdit::groupEq(gl[0], entryIn1_1));
    BOOST_CHECK(GroupEdit::groupEq(gl[1], entryIn2));

    gedit.edits.clear();
    entryIn1->mod->command = OFPGC11_DELETE;
    gedit.edits.push_back(entryIn1);
    BOOST_CHECK(fexec.Execute(gedit));
    gl.clear();
    rdr.GetGroups(gl);
    BOOST_CHECK(gl.size() == 1);
    BOOST_CHECK(GroupEdit::groupEq(gl[0], entryIn2));
}

BOOST_AUTO_TEST_SUITE_END()

void FlowModFixture::createTestFlows() {
    testFlows.push_back(FlowEntryPtr(new FlowEntry()));
    FlowEntry& e0 = *(testFlows.back());
    e0.entry->table_id = 0;
    e0.entry->priority = 100;
    e0.entry->cookie = 0xabcd;
    match_set_reg(&e0.entry->match, 3, 42);
    match_set_dl_type(&e0.entry->match, htons(ETH_TYPE_IP));
    match_set_nw_dst(&e0.entry->match, 0x01020304);
    ActionBuilder ab0;
    ab0.reg(MFF_REG0, 100);
    uint8_t mac[6] = {0xab, 0xcd, 0xef, 0xef, 0xcd, 0xab};
    ab0.ethSrc(mac);
    ab0.outputReg(MFF_REG7);
    ab0.controller();
    ab0.build(e0.entry);

    testFlows.push_back(FlowEntryPtr(new FlowEntry()));
    FlowEntry& e1 = *(testFlows.back());
    memcpy(e1.entry, e0.entry, sizeof(*e0.entry));
    ActionBuilder ab1;
    ab1.regMove(MFF_REG0, MFF_TUN_ID);
    ab1.go(10);
    ab1.build(e1.entry);
}

void FlowModFixture::compareFlows(const FlowEntry& lhs,
        const FlowEntry& rhs) {
    const ofputil_flow_stats& le = *(lhs.entry);
    const ofputil_flow_stats& re = *(rhs.entry);
    BOOST_CHECK(le.table_id == re.table_id);
    BOOST_CHECK(le.priority == re.priority);
    BOOST_CHECK(le.cookie == re.cookie);
    BOOST_CHECK(match_equal(&le.match, &re.match));
    BOOST_CHECK(ofpacts_equal(le.ofpacts, le.ofpacts_len,
                              re.ofpacts, re.ofpacts_len));
}

void FlowModFixture::removeDefaultFlows(FlowEntryList& newFlows) {
    match def;
    match_init_catchall(&def);

    FlowEntryList::iterator itr = newFlows.begin();
    while (itr != newFlows.end()) {
        if (match_equal(&def, &((*itr)->entry->match))) {
            itr = newFlows.erase(itr);
        } else {
            ++itr;
        }
    }
}

<commit_msg>Fix integration test to work with newer OVS.<commit_after>/*
 * Integration test suite for flow modifications.
 *
 * Copyright (c) 2014 Cisco Systems, Inc. and others.  All rights reserved.
 *
 * This program and the accompanying materials are made available under the
 * terms of the Eclipse Public License v1.0 which accompanies this distribution,
 * and is available at http://www.eclipse.org/legal/epl-v10.html
 */

#include <vector>
#include <boost/test/unit_test.hpp>
#include <boost/assign/list_inserter.hpp>
#include <boost/bind.hpp>
#include "logging.h"

#include "ovs.h"
#include "ConnectionFixture.h"
#include "FlowReader.h"
#include "FlowExecutor.h"
#include "ActionBuilder.h"

using namespace std;
using namespace boost;
using namespace ovsagent;

class BlockingFlowReader {
public:
    BlockingFlowReader(SwitchConnection *c) {
        conn = c;
        reader.installListenersForConnection(conn);
        cb = boost::bind(&BlockingFlowReader::gotFlow, this, _1, _2);
        gcb = boost::bind(&BlockingFlowReader::gotGroup, this, _1, _2);
    }
    ~BlockingFlowReader() {
        reader.uninstallListenersForConnection(conn);
    }

    void gotFlow(const FlowEntryList& flows, bool done) {
        recvFlows.insert(recvFlows.end(), flows.begin(), flows.end());
        replyDone = done;
    }
    void gotGroup(const GroupEdit::EntryList& groups, bool done) {
        recvGroups.insert(recvGroups.end(), groups.begin(), groups.end());
        replyDone = done;
    }

    void GetFlows(uint8_t tableId, FlowEntryList& flows) {
        recvFlows.clear();
        replyDone = false;
        reader.getFlows(tableId, cb);
        while (replyDone == false) {
            sleep(1);
        }
        flows.swap(recvFlows);
    }

    void GetGroups(GroupEdit::EntryList& groups) {
        recvGroups.clear();
        replyDone = false;
        reader.getGroups(gcb);
        while (replyDone == false) {
            sleep(1);
        }
        groups.swap(recvGroups);
    }

    SwitchConnection *conn;
    FlowReader reader;
    FlowReader::FlowCb cb;
    FlowEntryList recvFlows;
    FlowReader::GroupCb gcb;
    GroupEdit::EntryList recvGroups;
    bool replyDone;
};

class FlowModFixture : public ConnectionFixture,
                       public OnConnectListener {
public:
    FlowModFixture() : conn(testSwitchName), rdr(&conn), connectDone(false) {
        fexec.InstallListenersForConnection(&conn);
        conn.RegisterOnConnectListener(this);
        createTestFlows();
    }
    ~FlowModFixture() {
        conn.UnregisterOnConnectListener(this);
        fexec.UninstallListenersForConnection(&conn);
    }

    /** Interface: OnConnectListener */
    void Connected(SwitchConnection*) {
        connectDone = true;
    }

    void createTestFlows();

    void compareFlows(const FlowEntry& lhs, const FlowEntry& rhs);
    void removeDefaultFlows(FlowEntryList& newFlows);

    SwitchConnection conn;
    BlockingFlowReader rdr;
    FlowExecutor fexec;
    FlowEntryList testFlows;
    bool connectDone;
};

BOOST_AUTO_TEST_SUITE(flowmod_test)

BOOST_FIXTURE_TEST_CASE(simple_mod, FlowModFixture) {
    BOOST_REQUIRE(!conn.Connect(OFP13_VERSION));
    WAIT_FOR(connectDone == true, 5);

    FlowEdit fe;
    FlowEntryList flows;

    /* add */
    assign::push_back(fe.edits)(FlowEdit::ADD, testFlows[0]);
    BOOST_CHECK(fexec.Execute(fe));
    rdr.GetFlows(0, flows);
    removeDefaultFlows(flows);
    BOOST_CHECK(flows.size() == 1);
    compareFlows(*testFlows[0], *flows[0]);
    flows.clear();

    /* modify */
    fe.edits.clear();
    assign::push_back(fe.edits)(FlowEdit::MOD, testFlows[1]);
    BOOST_CHECK(fexec.Execute(fe));
    rdr.GetFlows(0, flows);
    removeDefaultFlows(flows);
    BOOST_CHECK(flows.size() == 1);
    compareFlows(*testFlows[1], *flows[0]);
    flows.clear();

    /* delete */
    fe.edits.clear();
    assign::push_back(fe.edits)(FlowEdit::DEL, testFlows[1]);
    BOOST_CHECK(fexec.Execute(fe));
    rdr.GetFlows(0, flows);
    removeDefaultFlows(flows);
    BOOST_CHECK(flows.size() == 0);
    flows.clear();
}

static
void addBucket(uint32_t bucketId, GroupEdit::Entry& entry) {
    ofputil_bucket *bkt = (ofputil_bucket *)malloc(sizeof(ofputil_bucket));
    bkt->weight = 0;
    bkt->bucket_id = bucketId;
    bkt->watch_port = OFPP_ANY;
    bkt->watch_group = OFPG11_ANY;

    ActionBuilder ab;
    ab.output(bucketId);
    ab.build(bkt);
    list_push_back(&entry->mod->buckets, &bkt->list_node);
}

BOOST_FIXTURE_TEST_CASE(group_mod, FlowModFixture) {
    BOOST_REQUIRE(!conn.Connect(OFP13_VERSION));
    WAIT_FOR(connectDone == true, 5);

    GroupEdit::Entry entryIn1(new GroupEdit::GroupMod());
    entryIn1->mod->command = OFPGC11_ADD;
    entryIn1->mod->group_id = 0;
    addBucket(10, entryIn1);
    addBucket(20, entryIn1);
    addBucket(30, entryIn1);

    GroupEdit::Entry entryIn1_1(new GroupEdit::GroupMod());
    entryIn1_1->mod->command = OFPGC11_MODIFY;
    entryIn1_1->mod->group_id = 0;
    addBucket(10, entryIn1_1);
    BOOST_CHECK(!GroupEdit::groupEq(entryIn1, entryIn1_1));

    GroupEdit::Entry entryIn2(new GroupEdit::GroupMod());
    entryIn2->mod->command = OFPGC11_ADD;
    entryIn2->mod->group_id = 1;
    addBucket(15, entryIn2);
    BOOST_CHECK(!GroupEdit::groupEq(entryIn1, entryIn2));

    GroupEdit gedit;
    gedit.edits.push_back(entryIn1);
    gedit.edits.push_back(entryIn2);
    BOOST_CHECK(fexec.Execute(gedit));

    GroupEdit::EntryList gl;
    rdr.GetGroups(gl);
    BOOST_REQUIRE(gl.size() == 2);
    BOOST_CHECK(GroupEdit::groupEq(gl[0], entryIn1));
    BOOST_CHECK(GroupEdit::groupEq(gl[1], entryIn2));

    gedit.edits.clear();
    gedit.edits.push_back(entryIn1_1);
    BOOST_CHECK(fexec.Execute(gedit));
    gl.clear();
    rdr.GetGroups(gl);
    BOOST_REQUIRE(gl.size() == 2);
    BOOST_CHECK(GroupEdit::groupEq(gl[0], entryIn1_1));
    BOOST_CHECK(GroupEdit::groupEq(gl[1], entryIn2));

    gedit.edits.clear();
    GroupEdit::Entry entryDel(new GroupEdit::GroupMod());
    entryDel->mod->command = OFPGC11_DELETE;
    entryDel->mod->group_id = 0;
    gedit.edits.push_back(entryDel);
    BOOST_CHECK(fexec.Execute(gedit));
    gl.clear();
    rdr.GetGroups(gl);
    BOOST_REQUIRE(gl.size() == 1);
    BOOST_CHECK(GroupEdit::groupEq(gl[0], entryIn2));
}

BOOST_AUTO_TEST_SUITE_END()

void FlowModFixture::createTestFlows() {
    testFlows.push_back(FlowEntryPtr(new FlowEntry()));
    FlowEntry& e0 = *(testFlows.back());
    e0.entry->table_id = 0;
    e0.entry->priority = 100;
    e0.entry->cookie = 0xabcd;
    match_set_reg(&e0.entry->match, 3, 42);
    match_set_dl_type(&e0.entry->match, htons(ETH_TYPE_IP));
    match_set_nw_dst(&e0.entry->match, 0x01020304);
    ActionBuilder ab0;
    ab0.reg(MFF_REG0, 100);
    uint8_t mac[6] = {0xab, 0xcd, 0xef, 0xef, 0xcd, 0xab};
    ab0.ethSrc(mac);
    ab0.outputReg(MFF_REG7);
    ab0.controller();
    ab0.build(e0.entry);

    testFlows.push_back(FlowEntryPtr(new FlowEntry()));
    FlowEntry& e1 = *(testFlows.back());
    memcpy(e1.entry, e0.entry, sizeof(*e0.entry));
    ActionBuilder ab1;
    ab1.regMove(MFF_REG0, MFF_TUN_ID);
    ab1.go(10);
    ab1.build(e1.entry);
}

void FlowModFixture::compareFlows(const FlowEntry& lhs,
        const FlowEntry& rhs) {
    const ofputil_flow_stats& le = *(lhs.entry);
    const ofputil_flow_stats& re = *(rhs.entry);
    BOOST_CHECK(le.table_id == re.table_id);
    BOOST_CHECK(le.priority == re.priority);
    BOOST_CHECK(le.cookie == re.cookie);
    BOOST_CHECK(match_equal(&le.match, &re.match));
    BOOST_CHECK(ofpacts_equal(le.ofpacts, le.ofpacts_len,
                              re.ofpacts, re.ofpacts_len));
}

void FlowModFixture::removeDefaultFlows(FlowEntryList& newFlows) {
    match def;
    match_init_catchall(&def);

    FlowEntryList::iterator itr = newFlows.begin();
    while (itr != newFlows.end()) {
        if (match_equal(&def, &((*itr)->entry->match))) {
            itr = newFlows.erase(itr);
        } else {
            ++itr;
        }
    }
}

<|endoftext|>


<commit_before>#include "musicdownloadqueryyytthread.h"
#include "musicsemaphoreloop.h"
#include "musicnumberutils.h"
#include "musictime.h"
#///QJson import
#include "qjson/parser.h"

const QString BD_MV_INFO_URL       = "dVBTZDgydDQvak9sYkp6c3VhYTZqV3k2NG9RK1dxcjNPYlZLWVZUWGx0aXlSRmY1YlBkV0ZGa0F5L2Y1U285M3VNTWtSYUI1N0tCRUNuK29VNUtqTXN6V0Y1TDZkYWJFS0Nqa280MjZHTnc4M1l3cUhqVldEOU9iblpSU0xvMzhSY0sxM1ZNRTZaUzM5RnhWRUJuWjRtdEJwWmFoNy9PYw==";
const QString BD_MV_INFO_ATTR_URL  = "S2p0SWNvNVNIVUEzV1QxOE83eTRsM0EwR3dGMUV2SXVNNWs1bW1iNUN1L0lxNHFCbXNCMDlkVjhZdFdzZGlvNVhJZzZOLzBUZE1MYjRnbGxkRzhiN2c9PQ==";

MusicDownLoadQueryYYTThread::MusicDownLoadQueryYYTThread(QObject *parent)
    : MusicDownLoadQueryThreadAbstract(parent)
{
    m_queryServer = "YinYueTai";
}

QString MusicDownLoadQueryYYTThread::getClassName()
{
    return staticMetaObject.className();
}

void MusicDownLoadQueryYYTThread::startToSearch(QueryType type, const QString &text)
{
    if(!m_manager)
    {
        return;
    }

    m_searchText = text.trimmed();
    m_currentType = type;
    QUrl musicUrl = MusicUtils::Algorithm::mdII(BD_MV_INFO_URL, false).arg(text);
    deleteAll();

    QNetworkRequest request;
    request.setUrl(musicUrl);
    request.setRawHeader("Content-Type", "application/x-www-form-urlencoded");
    request.setRawHeader("App-Id", "10201041");
    request.setRawHeader("Device-Id", "178bc560c9e8d719e048c7e8f2d25fcb");
    request.setRawHeader("Device-V", "QW5kcm9pZF80LjQuMl83NjgqMTE4NF8xMDAwMDEwMDA=");
#ifndef QT_NO_SSL
    QSslConfiguration sslConfig = request.sslConfiguration();
    sslConfig.setPeerVerifyMode(QSslSocket::VerifyNone);
    request.setSslConfiguration(sslConfig);
#endif
    m_reply = m_manager->get(request);
    connect(m_reply, SIGNAL(finished()), SLOT(downLoadFinished()));
    connect(m_reply, SIGNAL(error(QNetworkReply::NetworkError)), SLOT(replyError(QNetworkReply::NetworkError)));
}

void MusicDownLoadQueryYYTThread::downLoadFinished()
{
    if(m_reply == nullptr)
    {
        deleteAll();
        return;
    }

    emit clearAllItems();      ///Clear origin items
    m_musicSongInfos.clear();  ///Empty the last search to songsInfo

    if(m_reply->error() == QNetworkReply::NoError)
    {
        QByteArray bytes = m_reply->readAll();///Get all the data obtained by request
        QJson::Parser parser;
        bool ok;
        QVariant data = parser.parse(bytes, &ok);
        if(ok)
        {
            QVariantMap value = data.toMap();
            if(value.contains("code") && value["code"].toInt() == 0 &&
               value.contains("msg") && value["msg"].toString() == "SUCCESS")
            {
                QVariantList datas = value["data"].toList();
                foreach(const QVariant &var, datas)
                {
                    if(var.isNull())
                    {
                        continue;
                    }

                    value = var.toMap();

                    MusicObject::MusicSongInfomation musicInfo;
                    musicInfo.m_songId = QString::number(value["videoId"].toULongLong());
                    musicInfo.m_songName = value["title"].toString();

                    QVariantList artistsList = value["artists"].toList();
                    foreach(const QVariant &var, artistsList)
                    {
                        if(var.isNull())
                        {
                            continue;
                        }

                        value = var.toMap();
                        musicInfo.m_singerName = value["artistName"].toString();
                    }

                    if(!m_manager || m_stateCode != MusicNetworkAbstract::Init) return;
                    readFromMusicMVAttribute(&musicInfo, musicInfo.m_songId);
                    if(!m_manager || m_stateCode != MusicNetworkAbstract::Init) return;

                    if(musicInfo.m_songAttrs.isEmpty())
                    {
                        continue;
                    }
                    musicInfo.m_timeLength = musicInfo.m_songAttrs.first().m_duration;
                    MusicSearchedItem item;
                    item.m_songname = musicInfo.m_songName;
                    item.m_artistname = musicInfo.m_singerName;
                    item.m_time = musicInfo.m_timeLength;
                    item.m_type = mapQueryServerString();
                    emit createSearchedItems(item);

                    m_musicSongInfos << musicInfo;
                }
            }
        }
    }

    emit downLoadDataChanged(QString());
    deleteAll();
}

void MusicDownLoadQueryYYTThread::readFromMusicMVAttribute(MusicObject::MusicSongInfomation *info,
                                                           const QString &id)
{
    if(id.isEmpty() || !m_manager)
    {
        return;
    }

    QUrl musicUrl = MusicUtils::Algorithm::mdII(BD_MV_INFO_ATTR_URL, false).arg(id);

    QNetworkRequest request;
    request.setUrl(musicUrl);
    request.setRawHeader("Content-Type", "application/x-www-form-urlencoded");
    request.setRawHeader("App-Id", "10201041");
    request.setRawHeader("Device-Id", "178bc560c9e8d719e048c7e8f2d25fcb");
    request.setRawHeader("Device-V", "QW5kcm9pZF80LjQuMl83NjgqMTE4NF8xMDAwMDEwMDA=");
#ifndef QT_NO_SSL
    QSslConfiguration sslConfig = request.sslConfiguration();
    sslConfig.setPeerVerifyMode(QSslSocket::VerifyNone);
    request.setSslConfiguration(sslConfig);
#endif
    MusicSemaphoreLoop loop;
    QNetworkReply *reply = m_manager->get(request);
    QObject::connect(reply, SIGNAL(finished()), &loop, SLOT(quit()));
    QObject::connect(reply, SIGNAL(error(QNetworkReply::NetworkError)), &loop, SLOT(quit()));
    loop.exec();

    QJson::Parser parser;
    bool ok;
    QVariant data = parser.parse(reply->readAll(), &ok);
    if(ok)
    {
        QVariantMap value = data.toMap();
        if(value.contains("code") && value["code"].toInt() == 0 &&
           value.contains("msg") && value["msg"].toString() == "SUCCESS")
        {
            value = value["data"].toMap();
            QString duration = MusicTime::msecTime2LabelJustified(value["duration"].toInt()*1000);
            if(value.contains("hdUrl"))
            {
                readFromMusicMVInfoAttribute(info, value["hdUrl"].toString(),
                                             MusicUtils::Number::size2Label(value["hdVideoSize"].toInt()), duration);
            }
            if(value.contains("uhdUrl"))
            {
                readFromMusicMVInfoAttribute(info, value["uhdUrl"].toString(),
                                             MusicUtils::Number::size2Label(value["uhdVideoSize"].toInt()), duration);
            }
            if(value.contains("shdUrl"))
            {
                readFromMusicMVInfoAttribute(info, value["shdUrl"].toString(),
                                             MusicUtils::Number::size2Label(value["shdVideoSize"].toInt()), duration);
            }
        }
    }
}

void MusicDownLoadQueryYYTThread::readFromMusicMVInfoAttribute(MusicObject::MusicSongInfomation *info,
                                                               const QString &url, const QString &size, const QString &duration)
{
    if(url.isEmpty())
    {
        return;
    }

    QStringList datas = url.split("?");
    if(datas.count() == 2)
    {
        QString v = datas.front();
        MusicObject::MusicSongAttribute attr;
        attr.m_url = url;
        attr.m_size = size;
        attr.m_format = v.right(v.length() - v.lastIndexOf(".") - 1);
        attr.m_duration = duration;
        v = datas.back();
        foreach(QString var, v.split("&"))
        {
            if(var.contains("br="))
            {
                int bitRate = var.remove("br=").toInt();
                if(bitRate > 0 && bitRate <= 1000)
                    attr.m_bitrate = MB_500;
                else if(bitRate > 1000 && bitRate <= 2000)
                    attr.m_bitrate = MB_750;
                else if(bitRate > 2000)
                    attr.m_bitrate = MB_1000;
                else
                    attr.m_bitrate = bitRate;
            }
        }
        info->m_songAttrs.append(attr);
    }
}
<commit_msg>Encode url fixed[048556]<commit_after>#include "musicdownloadqueryyytthread.h"
#include "musicsemaphoreloop.h"
#include "musicnumberutils.h"
#include "musictime.h"
#///QJson import
#include "qjson/parser.h"

const QString BD_MV_INFO_URL       = "dVBTZDgydDQvak9sYkp6c3VhYTZqV3k2NG9RK1dxcjNPYlZLWVZUWGx0aXlSRmY1YlBkV0ZGa0F5L2Y1U285M3VNTWtSYUI1N0tCRUNuK29VNUtqTXN6V0Y1TDZkYWJFS0Nqa280MjZHTnc4M1l3cUhqVldEOU9iblpSU0xvMzhSY0sxM1ZNRTZaUzM5RnhWRUJuWjRtdEJwWmFoNy9PYw==";
const QString BD_MV_INFO_ATTR_URL  = "S2p0SWNvNVNIVUEzV1QxOE83eTRsM0EwR3dGMUV2SXVNNWs1bW1iNUN1L0lxNHFCbXNCMDlkVjhZdFdzZGlvNVhJZzZOLzBUZE1MYjRnbGxkRzhiN2c9PQ==";
const QString BD_MV_INFO_ID        = "Q3o1b2RqcE1Tam5Vc2FnSQ==";
const QString BD_MV_INFO_DID       = "R2hwbW1ZRVI0cjV2Qm1lT0RrQjBrbHVFN3hLUnJyWDh3VDYzeU5VemxoQUZ0bGtC";
const QString BD_MV_INFO_DV        = "cEoxTGtxZW9qQ1d0UHhZZWpabnNnSlBLTWV5Z055RThINHA2V3ZjNWs4V0RPUXVLekdoVE56Qzd2YW1YbEwwbQ==";

MusicDownLoadQueryYYTThread::MusicDownLoadQueryYYTThread(QObject *parent)
    : MusicDownLoadQueryThreadAbstract(parent)
{
    m_queryServer = "YinYueTai";
}

QString MusicDownLoadQueryYYTThread::getClassName()
{
    return staticMetaObject.className();
}

void MusicDownLoadQueryYYTThread::startToSearch(QueryType type, const QString &text)
{
    if(!m_manager)
    {
        return;
    }

    m_searchText = text.trimmed();
    m_currentType = type;
    QUrl musicUrl = MusicUtils::Algorithm::mdII(BD_MV_INFO_URL, false).arg(text);
    deleteAll();

    QNetworkRequest request;
    request.setUrl(musicUrl);
    request.setRawHeader("Content-Type", "application/x-www-form-urlencoded");
    request.setRawHeader("App-Id", MusicUtils::Algorithm::mdII(BD_MV_INFO_ID, false).toUtf8());
    request.setRawHeader("Device-Id", MusicUtils::Algorithm::mdII(BD_MV_INFO_DID, false).toUtf8());
    request.setRawHeader("Device-V", MusicUtils::Algorithm::mdII(BD_MV_INFO_DV, false).toUtf8());
#ifndef QT_NO_SSL
    QSslConfiguration sslConfig = request.sslConfiguration();
    sslConfig.setPeerVerifyMode(QSslSocket::VerifyNone);
    request.setSslConfiguration(sslConfig);
#endif
    m_reply = m_manager->get(request);
    connect(m_reply, SIGNAL(finished()), SLOT(downLoadFinished()));
    connect(m_reply, SIGNAL(error(QNetworkReply::NetworkError)), SLOT(replyError(QNetworkReply::NetworkError)));
}

void MusicDownLoadQueryYYTThread::downLoadFinished()
{
    if(m_reply == nullptr)
    {
        deleteAll();
        return;
    }

    emit clearAllItems();      ///Clear origin items
    m_musicSongInfos.clear();  ///Empty the last search to songsInfo

    if(m_reply->error() == QNetworkReply::NoError)
    {
        QByteArray bytes = m_reply->readAll();///Get all the data obtained by request
        QJson::Parser parser;
        bool ok;
        QVariant data = parser.parse(bytes, &ok);
        if(ok)
        {
            QVariantMap value = data.toMap();
            if(value.contains("code") && value["code"].toInt() == 0 &&
               value.contains("msg") && value["msg"].toString() == "SUCCESS")
            {
                QVariantList datas = value["data"].toList();
                foreach(const QVariant &var, datas)
                {
                    if(var.isNull())
                    {
                        continue;
                    }

                    value = var.toMap();

                    MusicObject::MusicSongInfomation musicInfo;
                    musicInfo.m_songId = QString::number(value["videoId"].toULongLong());
                    musicInfo.m_songName = value["title"].toString();

                    QVariantList artistsList = value["artists"].toList();
                    foreach(const QVariant &var, artistsList)
                    {
                        if(var.isNull())
                        {
                            continue;
                        }

                        value = var.toMap();
                        musicInfo.m_singerName = value["artistName"].toString();
                    }

                    if(!m_manager || m_stateCode != MusicNetworkAbstract::Init) return;
                    readFromMusicMVAttribute(&musicInfo, musicInfo.m_songId);
                    if(!m_manager || m_stateCode != MusicNetworkAbstract::Init) return;

                    if(musicInfo.m_songAttrs.isEmpty())
                    {
                        continue;
                    }
                    musicInfo.m_timeLength = musicInfo.m_songAttrs.first().m_duration;
                    MusicSearchedItem item;
                    item.m_songname = musicInfo.m_songName;
                    item.m_artistname = musicInfo.m_singerName;
                    item.m_time = musicInfo.m_timeLength;
                    item.m_type = mapQueryServerString();
                    emit createSearchedItems(item);

                    m_musicSongInfos << musicInfo;
                }
            }
        }
    }

    emit downLoadDataChanged(QString());
    deleteAll();
}

void MusicDownLoadQueryYYTThread::readFromMusicMVAttribute(MusicObject::MusicSongInfomation *info,
                                                           const QString &id)
{
    if(id.isEmpty() || !m_manager)
    {
        return;
    }

    QUrl musicUrl = MusicUtils::Algorithm::mdII(BD_MV_INFO_ATTR_URL, false).arg(id);

    QNetworkRequest request;
    request.setUrl(musicUrl);
    request.setRawHeader("Content-Type", "application/x-www-form-urlencoded");
    request.setRawHeader("App-Id", MusicUtils::Algorithm::mdII(BD_MV_INFO_ID, false).toUtf8());
    request.setRawHeader("Device-Id", MusicUtils::Algorithm::mdII(BD_MV_INFO_DID, false).toUtf8());
    request.setRawHeader("Device-V", MusicUtils::Algorithm::mdII(BD_MV_INFO_DV, false).toUtf8());
#ifndef QT_NO_SSL
    QSslConfiguration sslConfig = request.sslConfiguration();
    sslConfig.setPeerVerifyMode(QSslSocket::VerifyNone);
    request.setSslConfiguration(sslConfig);
#endif
    MusicSemaphoreLoop loop;
    QNetworkReply *reply = m_manager->get(request);
    QObject::connect(reply, SIGNAL(finished()), &loop, SLOT(quit()));
    QObject::connect(reply, SIGNAL(error(QNetworkReply::NetworkError)), &loop, SLOT(quit()));
    loop.exec();

    QJson::Parser parser;
    bool ok;
    QVariant data = parser.parse(reply->readAll(), &ok);
    if(ok)
    {
        QVariantMap value = data.toMap();
        if(value.contains("code") && value["code"].toInt() == 0 &&
           value.contains("msg") && value["msg"].toString() == "SUCCESS")
        {
            value = value["data"].toMap();
            QString duration = MusicTime::msecTime2LabelJustified(value["duration"].toInt()*1000);
            if(value.contains("hdUrl"))
            {
                readFromMusicMVInfoAttribute(info, value["hdUrl"].toString(),
                                             MusicUtils::Number::size2Label(value["hdVideoSize"].toInt()), duration);
            }
            if(value.contains("uhdUrl"))
            {
                readFromMusicMVInfoAttribute(info, value["uhdUrl"].toString(),
                                             MusicUtils::Number::size2Label(value["uhdVideoSize"].toInt()), duration);
            }
            if(value.contains("shdUrl"))
            {
                readFromMusicMVInfoAttribute(info, value["shdUrl"].toString(),
                                             MusicUtils::Number::size2Label(value["shdVideoSize"].toInt()), duration);
            }
        }
    }
}

void MusicDownLoadQueryYYTThread::readFromMusicMVInfoAttribute(MusicObject::MusicSongInfomation *info,
                                                               const QString &url, const QString &size, const QString &duration)
{
    if(url.isEmpty())
    {
        return;
    }

    QStringList datas = url.split("?");
    if(datas.count() == 2)
    {
        QString v = datas.front();
        MusicObject::MusicSongAttribute attr;
        attr.m_url = url;
        attr.m_size = size;
        attr.m_format = v.right(v.length() - v.lastIndexOf(".") - 1);
        attr.m_duration = duration;
        v = datas.back();
        foreach(QString var, v.split("&"))
        {
            if(var.contains("br="))
            {
                int bitRate = var.remove("br=").toInt();
                if(bitRate > 0 && bitRate <= 1000)
                    attr.m_bitrate = MB_500;
                else if(bitRate > 1000 && bitRate <= 2000)
                    attr.m_bitrate = MB_750;
                else if(bitRate > 2000)
                    attr.m_bitrate = MB_1000;
                else
                    attr.m_bitrate = bitRate;
            }
        }
        info->m_songAttrs.append(attr);
    }
}
<|endoftext|>