Ntuple producer for top analysis

The CATTuple dataformat leaves detailed object selection, candidate combinations and kinematic fit to users.
User level macro can be written but usually it is not suitable to treat complicated analysis objects like candidate combinations, kinematic fits and cut optimization.

To reconstruct top quarks in dilepton channel, all of those works should be done. Also this is CPU intensive job in general, thus dedicated analyzer is necessary.
Traditionally, we wrote an EDAnalyzer to do candidate combinations, kinematic fits and fill into ntuples - but storing the result in edm format is more clever way to manage the results. Ntuple producers can be run after running all analysis object producers and then merge all of them into single ntuple.

A generic purpose ntuple producer based on EDM candidate model is imported from the KrAFT tool with small modifications. This module is fully configurable to select any variables of object inherited from reco::Candidate.
Control plots such as muon pt, eta can be easily produced just putting parameterSet for them.

Working (and most complicated) example is given below:
```python
process.ntuple.cands.ttbar = cms.PSet(
            src = cms.InputTag("ttbar"),
            index = cms.untracked.int32(0),
            exprs = cms.untracked.PSet(
                pt  = cms.string("pt"),
                eta = cms.string("eta"),
                phi = cms.string("phi"),
                m   = cms.string("mass"),

                top1pt  = cms.string("daughterPtr(0).pt"),
                top1eta = cms.string("daughterPtr(0).eta"),
                top1phi = cms.string("daughterPtr(0).phi"),
                top1m   = cms.string("daughterPtr(0).mass"),

                top2pt  = cms.string("daughterPtr(1).pt"),
                top2eta = cms.string("daughterPtr(1).eta"),
                top2phi = cms.string("daughterPtr(1).phi"),
                top2m   = cms.string("daughterPtr(1).mass"),

                w1m   = cms.string("daughterPtr(0).daughter(0).mass"),
                w2m   = cms.string("daughterPtr(1).daughter(0).mass"),
                b1Pt = cms.string("daughterPtr(0).daughter(1).pt"),
                b2Pt = cms.string("daughterPtr(1).daughter(1).pt"),
                b1Tag = cms.string("daughterPtr(0).daughter(1).bDiscriminator('combinedInclusiveSecondaryVertexV2BJetTags')"),
                b2Tag = cms.string("daughterPtr(1).daughter(1).bDiscriminator('combinedInclusiveSecondaryVertexV2BJetTags')"),

                lep1Pt = cms.string("daughter(0).daughter(0).daughter(0).pt"),
                lep2Pt = cms.string("daughter(1).daughter(0).daughter(0).pt"),
                nu1Pt = cms.string("daughter(0).daughter(0).daughter(1).pt"),
                nu2Pt = cms.string("daughter(1).daughter(0).daughter(1).pt"),
            ),
        )
```

Note that we added b-Tag info with just one line string, no C++!

Summarizing up, I'm adding 3rd step of workflow:

AOD -> (MINIAOD -> CATTuple) -> (TTbarDileptonProducer -> GenericNtupleMaker)

Here we can feed any kind of producers' output into the GenericNtupleMaker such as gen level objects, Higgs producers, Jpsi producers, etc.